Beatmup
region_filling.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 "../bitmap/abstract_bitmap.h"
21 #include "../geometry.h"
22 #include <queue>
23 #include <mutex>
24 
25 using namespace Beatmup;
26 
27 namespace Kernels {
28  /**
29  Region filling kernel implementing flood fill starting from a given seed
30  */
31  template<typename in_t, typename out_t> class FillRegion {
32  public:
33  typedef typename in_t::pixtype::operating_type inpixvaltype;
34  /**
35  Fills a region in an output bitmap starting from a given position in an input bitmap
36  \param input Input bitmap reader
37  \param output Output mask writer
38  \param maskOffset Mask position in the bitmap
39  \param seed Entry point
40  \param tolerance Tolerance level: how much a pixel has to be different from seed to not to be filled
41  \param border A vector to put border points to for further processing
42  \param bounds Bounding box of the filled region; the input value is updated but not reset
43  */
44  static void process(
45  AbstractBitmap& input,
46  AbstractBitmap& output,
47  IntPoint maskOffset,
48  IntPoint seed,
50  std::vector<IntPoint>& border,
51  IntRectangle& bounds
52  ) {
53  in_t in(input);
54  out_t out(output);
55 
56  const int
57  W = in.getWidth() - 1, H = in.getHeight() - 1,
58  MW = out.getWidth() - 1, MH = out.getHeight() - 1;
59 
60  std::queue<IntPoint> queue;
61  queue.push(IntPoint(seed.x, seed.y));
62  in.goTo(seed.x, seed.y);
63 
64  const typename in_t::pixtype ref = in(); // reference input value
65  const int range = out.MAX_UNNORM_VALUE;
66 
67  inpixvaltype diff;
68  unsigned char newval, oldval;
69 
70  // performance critical cycle
71  while (!queue.empty()) {
72  // popping from queue front
73  IntPoint p = queue.front();
74  queue.pop();
75  int
76  mx = p.x - maskOffset.x,
77  my = p.y - maskOffset.y;
78 
79  // checking neighbor pixels
80  bool onBorder = false;
81 
82  if (p.x > 0 && mx > 0 && (diff = (in(p.x - 1, p.y) - ref).abs().max()) <= tolerance) {
83  newval = (tolerance > 0 && diff > 0) ? (range * (tolerance - diff) / tolerance + 1) : out.MAX_UNNORM_VALUE;
84  out.goTo(mx - 1, my);
85  oldval = out.getValue();
86  if (oldval < newval) {
87  out.putValue(newval);
88  queue.push(IntPoint(p.x - 1, p.y));
89  }
90  }
91  else onBorder = true;
92 
93  if (p.y > 0 && my > 0 && (diff = (in(p.x, p.y - 1) - ref).abs().max()) <= tolerance) {
94  newval = (tolerance > 0 && diff > 0) ? (range * (tolerance - diff) / tolerance + 1) : out.MAX_UNNORM_VALUE;
95  out.goTo(mx, my - 1);
96  oldval = out.getValue();
97  if (oldval < newval) {
98  out.putValue(newval);
99  queue.push(IntPoint(p.x, p.y - 1));
100  }
101  }
102  else onBorder = true;
103 
104  if (p.x < W && mx < MW && (diff = (in(p.x + 1, p.y) - ref).abs().max()) <= tolerance) {
105  newval = (tolerance > 0 && diff > 0) ? (range * (tolerance - diff) / tolerance + 1) : out.MAX_UNNORM_VALUE;
106  out.goTo(mx + 1, my);
107  oldval = out.getValue();
108  if (oldval < newval) {
109  out.putValue(newval);
110  queue.push(IntPoint(p.x + 1, p.y));
111  }
112  }
113  else onBorder = true;
114 
115  if (p.y < H && my < MH && (diff = (in(p.x, p.y + 1) - ref).abs().max()) <= tolerance) {
116  newval = (tolerance > 0 && diff > 0) ? (range * (tolerance - diff) / tolerance + 1) : out.MAX_UNNORM_VALUE;
117  out.goTo(mx, my + 1);
118  oldval = out.getValue();
119  if (oldval < newval) {
120  out.putValue(newval);
121  queue.push(IntPoint(p.x, p.y + 1));
122  }
123  }
124  else onBorder = true;
125 
126  if (onBorder) {
127  border.push_back(IntPoint(mx, my));
128 
129  if (mx < bounds.a.x)
130  bounds.a.x = mx;
131  if (mx > bounds.b.x)
132  bounds.b.x = mx;
133  if (my < bounds.a.y)
134  bounds.a.y = my;
135  if (my > bounds.b.y)
136  bounds.b.y = my;
137  }
138  }
139  }
140  };
141 
142 
143  /**
144  Circular dilatation kernel for flood fill contours postprocessing
145  */
146  template<typename out_t> class CircularDilatation {
147  public:
148  /**
149  Circular dilatation of a mask at given points
150  \param bitmap The mask bitmap
151  \param pointSet The points
152  \param val Max value (amplitude)
153  \param holdRad Inner kernel radius; all pixels inside take `val` value
154  \param releaseRad Release ring outer radius; all pixels in the ring take linearly attenuated `val` value
155  */
156  static void process(AbstractBitmap& bitmap, std::vector<IntPoint>& pointSet, int val, float holdRad, float releaseRad) {
157  out_t mask(bitmap);
158  const int morphoSize = (int)ceilf(holdRad + releaseRad);
159  const float morphoReleaseRing = releaseRad - holdRad;
160  // for each point in the point set...
161  for (auto p : pointSet) {
162  // determine a bounding box to apply the kernel
163  int
164  x1 = std::max(0, p.x - morphoSize),
165  y1 = std::max(0, p.y - morphoSize),
166  x2 = std::min(mask.getWidth() - 1, p.x + morphoSize),
167  y2 = std::min(mask.getHeight() - 1, p.y + morphoSize);
168  // apply the kernel
169  for (int y = y1; y <= y2; ++y) {
170  mask.goTo(x1, y);
171  for (int x = x1; x <= x2; ++x, mask++) {
172  // squared distance to center
173  int d2 = sqr(x - p.x) + sqr(y - p.y);
174  if (d2 < sqr(holdRad))
175  mask.assign(val);
176  else if (d2 < sqr(releaseRad)) {
177  // linear attenuation
178  int c = (int)roundf((float)val * (1.0f - (sqrtf((float)d2) - holdRad) / morphoReleaseRing));
179  if (mask().x < c)
180  mask.assign(c);
181  }
182  }
183  }
184  }
185  }
186  };
187 
188 
189  /**
190  Circular erosion kernel for flood fill contours postprocessing
191  */
192  template<typename out_t> class CircularErosion {
193  public:
194  /**
195  Circular erosion of a mask at given points
196  \param bitmap The mask bitmap
197  \param pointSet The points
198  \param val Max value (amplitude)
199  \param holdRad Inner kernel radius; all pixels inside take `val` value
200  \param releaseRad Release ring outer radius; all pixels in the ring take linearly attenuated `val` value
201  */
202  static void process(AbstractBitmap& bitmap, std::vector<IntPoint>& pointSet, int val, float holdRad, float releaseRad) {
203  out_t mask(bitmap);
204  const int morphoSize = (int)ceilf(holdRad + releaseRad);
205  const float morphoReleaseRing = releaseRad - holdRad;
206  // for each point in the point set...
207  for (auto p : pointSet) {
208  // determine a bounding box to apply the kernel
209  int
210  x1 = std::max(0, p.x - morphoSize),
211  y1 = std::max(0, p.y - morphoSize),
212  x2 = std::min(mask.getWidth() - 1, p.x + morphoSize),
213  y2 = std::min(mask.getHeight() - 1, p.y + morphoSize);
214  // apply the kernel
215  for (int y = y1; y <= y2; ++y) {
216  mask.goTo(x1, y);
217  for (int x = x1; x <= x2; ++x, mask++) {
218  // squared distance to center
219  int d2 = sqr(x - p.x) + sqr(y - p.y);
220  if (d2 < sqr(holdRad))
221  mask.assign(0);
222  else if (d2 < sqr(releaseRad)) {
223  // linear attenuation
224  int c = (int)roundf((float)val * (sqrtf((float)d2) - holdRad) / morphoReleaseRing);
225  if (mask().x > c)
226  mask.assign(c);
227  }
228  }
229  }
230  }
231  }
232  };
233 }
A very basic class for any image.
CustomPoint< numeric > b
Definition: geometry.h:131
CustomPoint< numeric > a
Definition: geometry.h:131
Circular dilatation kernel for flood fill contours postprocessing.
static void process(AbstractBitmap &bitmap, std::vector< IntPoint > &pointSet, int val, float holdRad, float releaseRad)
Circular dilatation of a mask at given points.
Circular erosion kernel for flood fill contours postprocessing.
static void process(AbstractBitmap &bitmap, std::vector< IntPoint > &pointSet, int val, float holdRad, float releaseRad)
Circular erosion of a mask at given points.
Region filling kernel implementing flood fill starting from a given seed.
in_t::pixtype::operating_type inpixvaltype
static void process(AbstractBitmap &input, AbstractBitmap &output, IntPoint maskOffset, IntPoint seed, inpixvaltype tolerance, std::vector< IntPoint > &border, IntRectangle &bounds)
Fills a region in an output bitmap starting from a given position in an input bitmap.
#define sqr(X)
Definition: geometry.h:24
CustomPoint< int > IntPoint
Definition: geometry.h:629
Operations kernels.
Definition: basic_types.h:85
CustomPoint< numeric > min(const CustomPoint< numeric > &a, const CustomPoint< numeric > &b)
Definition: geometry.h:724
CustomPoint< numeric > max(const CustomPoint< numeric > &a, const CustomPoint< numeric > &b)
Definition: geometry.h:728
JNIEnv jlong jint jint jint jint y2
JNIEnv jlong jint x1
JNIEnv jlong jint jint jint x2
JNIEnv jlong jint jint jint y1
jobject jlong jint jint y
jobject jlong jint x
return(jlong) new Beatmup jlong jstring jint val
JNIEnv jlong jint out
Beatmup::InternalBitmap * bitmap
Beatmup::IntPoint p((int) x,(int) y)
jlong jfloat tolerance