Beatmup
resampling_kernels.h
Go to the documentation of this file.
1 /*
2  Beatmup image and signal processing library
3  Copyright (C) 2019, lnstadrum
4 
5  This program is free software: you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation, either version 3 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18 
19 #pragma once
20 #include "../parallelism.h"
21 #include "../geometry.h"
22 #include <algorithm>
23 
24 using namespace Beatmup;
25 
26 namespace Kernels {
27 
28  template<class in_t, class out_t> class NearestNeighborResampling {
29  public:
30 
31  /**
32  Resamples a rectangle from an input bitmap to a rectangle in an output bitmap by nearest neighbor interpolation
33  */
34  static void process(AbstractBitmap& input, AbstractBitmap& output, IntRectangle& src, IntRectangle& dst, const TaskThread& tt) {
35  in_t in(input);
36  out_t out(output);
37 
38  const int
39  srcW = src.width(), srcH = src.height(),
40  dstW = dst.width(), dstH = dst.height(),
41  shiftX = srcW / 2,
42  shiftY = srcH / 2;
43 
44  // dest image slice to process in the current thread
45  const int
46  sliceStart = tt.currentThread() * dstH / tt.numThreads(),
47  sliceStop = (tt.currentThread() + 1) * dstH / tt.numThreads();
48 
49  for (int y = sliceStart; y < sliceStop; ++y) {
50  out.goTo(dst.a.x, dst.a.y + y);
51  const int sy = src.a.y + (y * srcH + shiftY) / dstH;
52 
53  for (int x = 0; x < dstW; ++x) {
54  const int sx = src.a.x + (x * srcW + shiftX) / dstW;
55  in.goTo(sx, sy);
56  out = in();
57  out++;
58  }
59 
60  if (tt.isTaskAborted())
61  return;
62  }
63  }
64  };
65 
66 
67  template<class in_t, class out_t> class BoxResampling {
68  public:
69 
70  /**
71  Resamples a rectangle from an input bitmap to a rectangle in an output bitmap applying a box filter
72  */
73  static void process(AbstractBitmap& input, AbstractBitmap& output, IntRectangle& src, IntRectangle& dst, const TaskThread& tt) {
74  in_t in(input);
75  out_t out(output);
76 
77  const int
78  srcW = src.width(), srcH = src.height(),
79  dstW = dst.width(), dstH = dst.height();
80 
81  // dest image slice to process in the current thread
82  const int
83  sliceStart = tt.currentThread() * dstH / tt.numThreads(),
84  sliceStop = (tt.currentThread() + 1) * dstH / tt.numThreads();
85 
86  int x0, y0, x1, y1 = src.a.y + (sliceStart) * srcH / dstH; // coordinates of source pixels box mapped to a given dest pixel
87 
88  typename in_t::pixtype acc;
89  for (int y = sliceStart; y < sliceStop; ++y) {
90  out.goTo(dst.a.x, dst.a.y + y);
91  y0 = y1;
92  y1 = src.a.y + (y + 1) * srcH / dstH;
93  x1 = src.a.x;
94  for (int x = 0; x < dstW; ++x) {
95  x0 = x1;
96  x1 = src.a.x + (x + 1) * srcW / dstW;
97 
98  // loop over the source area
99  acc.zero();
100  int y = y0;
101  do {
102  in.goTo(x0, y);
103  int x = x0;
104  do {
105  acc = acc + in();
106  in++;
107  } while (++x < x1);
108  } while (++y < y1);
109 
110  // write out
111  out = acc / std::max(1, (x1 - x0)*(y1 - y0));
112  out++;
113  }
114 
115  if (tt.isTaskAborted())
116  return;
117  }
118  }
119  };
120 
121 
122  template<class in_t, class out_t> class BilinearResampling {
123  public:
124 
125  /**
126  Resamples a rectangle from an input bitmap to a rectangle in an output bitmap by bilinear interpolation
127  */
128  static void process(AbstractBitmap& input, AbstractBitmap& output, IntRectangle& src, IntRectangle& dst, const TaskThread& tt) {
129  in_t in(input);
130  out_t out(output);
131 
132  const int
133  srcW = src.width(), srcH = src.height(),
134  dstW = dst.width(), dstH = dst.height(),
135  shiftX = (srcW - dstW) / 2,
136  shiftY = (srcH - dstH) / 2;
137 
138  // dest image slice to process in the current thread
139  const int
140  sliceStart = tt.currentThread() * dstH / tt.numThreads(),
141  sliceStop = (tt.currentThread() + 1) * dstH / tt.numThreads();
142 
143  for (int y = sliceStart; y < sliceStop; ++y) {
144  out.goTo(dst.a.x, dst.a.y + y);
145  const float fsy = (float)(y * srcH + shiftY) / dstH;
146  const int isy = (int)fsy;
147  const float fy = fsy - (float)isy, _fy = 1 - fy;
148  const int sy = src.a.y + isy;
149 
150  const int
151  lineJump = sy < srcH - 1 ? srcW - 1 : -1,
152  xBound = srcW - 1;
153 
154  typename out_t::pixtype acc;
155  for (int x = 0; x < dstW; ++x) {
156 
157  const float fsx = (float)(x * srcW + shiftX) / dstW;
158  const int isx = (int)fsx;
159  const float fx = fsx - (float)isx;
160  const int sx = src.a.x + isx;
161 
162  in.goTo(sx, sy);
163  if (sx < xBound) {
164  acc = in() * (1 - fx) * _fy;
165  in++;
166  acc = acc + in() * fx * _fy;
167  in += lineJump;
168  acc = acc + in() * (1 - fx) * fy;
169  in++;
170  acc = acc + in() * fx * fy;
171  }
172  else {
173  acc = in() * _fy;
174  in += lineJump + 1;
175  acc = acc + in() * fy;
176  }
177 
178  out = acc;
179  out++;
180  }
181 
182  if (tt.isTaskAborted())
183  return;
184  }
185  }
186  };
187 
188 
189  template<class in_t, class out_t> class BicubicResampling {
190  private:
191  /**
192  Precomputes kernel coefficients in function of bicubic kernel parameter.
193  */
195  private:
196  float c0[2], c1[2], c2[3];
197  float coeff[4];
198  public:
199  BicubicKernel(const float alpha) {
200  // alpha*x**3 - 2*alpha*x**2 + alpha*x
201  c0[0] = alpha;
202  c0[1] = -2 * alpha;
203  //alpha*x**3 - alpha*x**2 + 2*x**3 - 3*x**2 + 1
204  c1[0] = - alpha - 3;
205  c1[1] = alpha + 2;
206  // -alpha*x**3 + 2*alpha*x**2 - alpha*x - 2*x**3 + 3*x**2
207  c2[0] = -alpha;
208  c2[1] = 2 * alpha + 3;
209  c2[2] = - alpha - 2;
210  }
211 
212  /**
213  Computes the kernel itself for a given phase.
214  */
215  void operator()(float x) {
216  const float xx = x * x, xxx = xx * x;
217  coeff[0] = c0[0] * (xxx + x) + c0[1] * xx;
218  coeff[1] = c1[1] * xxx + c1[0] * xx + 1;
219  coeff[2] = c2[2] * xxx + c2[1] * xx + c2[0] * x;
220  coeff[3] = 1 - coeff[0] - coeff[1] - coeff[2];
221  }
222 
223  inline const float operator[](const int i) const {
224  return coeff[i];
225  }
226  };
227 
228  public:
229  /**
230  Resamples a rectangle from an input bitmap to a rectangle in an output bitmap applying a bicubic kernel
231  */
232  static void process(AbstractBitmap& input, AbstractBitmap& output, IntRectangle& src, IntRectangle& dst, const float alpha, const TaskThread& tt) {
233  in_t in(input);
234  out_t out(output);
235 
236  const int
237  srcW = src.width(), srcH = src.height(),
238  dstW = dst.width(), dstH = dst.height(),
239  shiftX = (srcW - dstW) / 2,
240  shiftY = (srcH - dstH) / 2;
241 
242  // dest image slice to process in the current thread
243  const int
244  sliceStart = tt.currentThread() * dstH / tt.numThreads(),
245  sliceStop = (tt.currentThread() + 1) * dstH / tt.numThreads();
246 
247  BicubicKernel kx(alpha), ky(alpha);
248 
249  for (int y = sliceStart; y < sliceStop; ++y) {
250  out.goTo(dst.a.x, dst.a.y + y);
251  const float fsy = (float)(y * srcH + shiftY) / dstH;
252  const int isy = (int)fsy;
253  const float fy = fsy - (float)isy;
254  const int sy = src.a.y + isy;
255 
256  const int lineJump[3] = {
257  sy > 0 ? srcW : 0,
258  sy < srcH - 1 ? srcW : 0,
259  sy < srcH - 2 ? srcW : 0
260  };
261 
262  // preparing kernel
263  ky(fy);
264 
265  typename out_t::pixtype acc;
266  for (int x = 0; x < dstW; ++x) {
267 
268  const float fsx = (float)(x * srcW + shiftX) / dstW;
269  const int isx = (int)fsx;
270  const float fx = fsx - (float)isx;
271  const int sx = src.a.x + isx;
272 
273  kx(fx);
274 
275  const int pixJump[3] = {
276  sx > 0 ? -1 : 0,
277  sx < srcW - 1 ? +1 : 0,
278  sx < srcW - 2 ? +2 : 0
279  };
280 
281  in.goTo(sx, sy > 0 ? sy - 1 : 0);
282  acc = in[pixJump[0]] * kx[0] * ky[0] + in() * kx[1] * ky[0] + in[pixJump[1]] * kx[2] * ky[0] + in[pixJump[2]] * kx[3] * ky[0];
283  in += lineJump[0];
284  acc = acc + in[pixJump[0]] * kx[0] * ky[1] + in() * kx[1] * ky[1] + in[pixJump[1]] * kx[2] * ky[1] + in[pixJump[2]] * kx[3] * ky[1];
285  in += lineJump[1];
286  acc = acc + in[pixJump[0]] * kx[0] * ky[2] + in() * kx[1] * ky[2] + in[pixJump[1]] * kx[2] * ky[2] + in[pixJump[2]] * kx[3] * ky[2];
287  in += lineJump[2];
288  acc = acc + in[pixJump[0]] * kx[0] * ky[3] + in() * kx[1] * ky[3] + in[pixJump[1]] * kx[2] * ky[3] + in[pixJump[2]] * kx[3] * ky[3];
289 
290  out = acc;
291  out++;
292  }
293 
294  if (tt.isTaskAborted())
295  return;
296  }
297  }
298  };
299 }
A very basic class for any image.
numeric height() const
Definition: geometry.h:178
numeric width() const
Definition: geometry.h:174
CustomPoint< numeric > a
Definition: geometry.h:131
Thread executing tasks.
Definition: parallelism.h:154
virtual ThreadIndex numThreads() const =0
ThreadIndex currentThread() const
Definition: parallelism.h:165
virtual bool isTaskAborted() const =0
Returns true if the task is asked to stop from outside.
Precomputes kernel coefficients in function of bicubic kernel parameter.
void operator()(float x)
Computes the kernel itself for a given phase.
const float operator[](const int i) const
static void process(AbstractBitmap &input, AbstractBitmap &output, IntRectangle &src, IntRectangle &dst, const float alpha, const TaskThread &tt)
Resamples a rectangle from an input bitmap to a rectangle in an output bitmap applying a bicubic kern...
static void process(AbstractBitmap &input, AbstractBitmap &output, IntRectangle &src, IntRectangle &dst, const TaskThread &tt)
Resamples a rectangle from an input bitmap to a rectangle in an output bitmap by bilinear interpolati...
static void process(AbstractBitmap &input, AbstractBitmap &output, IntRectangle &src, IntRectangle &dst, const TaskThread &tt)
Resamples a rectangle from an input bitmap to a rectangle in an output bitmap applying a box filter.
static void process(AbstractBitmap &input, AbstractBitmap &output, IntRectangle &src, IntRectangle &dst, const TaskThread &tt)
Resamples a rectangle from an input bitmap to a rectangle in an output bitmap by nearest neighbor int...
Operations kernels.
Definition: basic_types.h:85
CustomPoint< numeric > max(const CustomPoint< numeric > &a, const CustomPoint< numeric > &b)
Definition: geometry.h:728
JNIEnv jlong jint x1
JNIEnv jlong jint jint jint y1
jobject jlong jint jint y
jobject jlong jint x
JNIEnv jlong jint out
return(jlong) new Beatmup jlong jstring src