Beatmup
contours.cpp
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 #include "contours.h"
20 #include "../bitmap/processing.h"
21 #include <algorithm>
22 #include <cstdlib> // because of std::abs stuff on integer numbers
23 using namespace Beatmup;
24 
25 
26 namespace Kernels {
27  template<class in_t> class ComputeBounds {
28  public:
29  static void process(AbstractBitmap& bitmap, std::vector<IntegerContour2D*>& boundary, std::vector<IntPoint>& border, BinaryMaskWriter& testedPixels, float level) {
30  in_t in(bitmap);
31 
32  typedef struct {
33  int x, y;
34  } Displacement;
35 
36  // clockwise direction lookup in function of four neighbour values
37  const Displacement LOOKUP_DIRECTION[2][2][2][2] = {
38  //rb //lb //rb+lb //rt //rt+rb //rt+lb //rt+lb+rb
39  { { { { 0, 0 }, { 1, 0 } }, { { 0, +1 }, { +1, 0 } } }, { { { 0, -1 }, { 0, -1 } }, { { 9, 9 }, { 0, -1 } } } },
40  //lt //lt+rb //lt+lb //lt+lb+rb //lt+rt //lt+rt+rb //lt+rt+lb
41  { { { { -1, 0 }, { 9, 9 } }, { { 0, 1 }, { +1, 0 } } }, { { { -1, 0 }, { -1, 0 } }, { { 0, 1 }, { 0, 0 } } } }
42  };
43 
44  const Displacement LOOKUP_INTERNAL_PIXEL[3][3] = {
45  { { 0, 0 }, { 0, -1 }, { 0, 0 } },
46  { { -1, -1 }, { 9, 0 }, { 0, 0 } },
47  { { 0, 0 }, { -1, 0 }, { 0, 0 } }
48  };
49 
50  const int W = in.getWidth(), H = in.getHeight();
51  const float LEVEL = level * in.MAX_VALUE;
52  IntPoint seed;
53  int x, y;
54 
55  // scanning boundary pixels
56  for (auto seed : border) {
57 
58  // picking a seed
59  x = seed.x;
60  y = seed.y;
61  testedPixels.goTo(x, y);
62  if (testedPixels.getValue() > 0)
63  continue;
64  testedPixels.putValue(1);
65 
66  // a good seed has one neighboring point inside
67  int ctr = 0;
68  if (x < W && y < H && in().mean() > LEVEL) ++ctr;
69  if (x > 0 && y < H && in(x - 1, y).mean() > LEVEL) ++ctr;
70  if (x < W && y > 0 && in(x, y - 1).mean() > LEVEL) ++ctr;
71  if (x > 0 && y > 0 && in(x - 1, y - 1).mean() > LEVEL) ++ctr;
72  if (ctr != 1)
73  continue;
74 
75  // good seed found: go
76  in.goTo(x, y);
77  Displacement prev = { 0, 0 };
78  IntegerContour2D* contour = new IntegerContour2D();
79  boundary.push_back(contour);
80 
81  // go
82  do {
83  // binarize the neighbours
84  bool
85  rb = x < W && y < H && in().mean() > LEVEL,
86  lb = x > 0 && y < H && in(x - 1, y).mean() > LEVEL,
87  rt = x < W && y > 0 && in(x, y - 1).mean() > LEVEL,
88  lt = x > 0 && y > 0 && in(x - 1, y - 1).mean() > LEVEL;
89 
90  // check the point: must have a neighbor inside and a neighbor outside
91  if ((rb && lb && rt && lt) || !(rb || lb || rt || lt))
92  throw IntegerContour2D::BadSeedPoint(x, y, lt, rt, lb, rb);
93 
94  // add the point
95  contour->addPoint(x, y);
96 
97  // compute step direction
98  Displacement d = LOOKUP_DIRECTION[lt][rt][lb][rb];
99  if (d.x == 9) { // special case: displacement depends on the previous direction
100  if (prev.x == 0 && prev.y == 0)
101  throw IntegerContour2D::BadSeedPoint(x, y, lt, rt, lb, rb);
102  d.x = -prev.y;
103  d.y = prev.x;
104  }
105 
106  // marking used pixel
107  Displacement ip = LOOKUP_INTERNAL_PIXEL[d.y + 1][d.x + 1];
108  int ipx = x + ip.x, ipy = y + ip.y;
109  if (ipx >= 0 && ipy >= 0 && ipx < W && ipy < H) {
110  testedPixels.goTo(ipx, ipy);
111  testedPixels.putValue(1);
112  }
113 
114  // step
115  x += d.x;
116  y += d.y;
117  prev = d;
118 
119  if (x < W && y < H)
120  in.goTo(x, y);
121 
122  } while (seed.x != x || seed.y != y);
123 
124  // adding the last point
125  contour->addPoint(x, y);
126  }
127  }
128  };
129 }
130 
131 
133  totalLength(0.0f), lastFragmentLength(0.0f)
134 {}
135 
136 
138  // check for update
139  if (points.size() > 2) {
140  IntPoint& p1 = points.back();
141  IntPoint p2 = points[points.size() - 2];
142  if (
143  (std::max(abs(x - p1.x), abs(y - p1.y)) <= 1 && std::max(abs(x - p2.x), abs(y - p2.y)) <= 1) ||
144  (x != p1.x && (p1.y - y) * (p2.x - p1.x) == (p2.y - p1.y) * (p1.x - x)) ||
145  (y != p1.y && (p1.x - x) * (p2.y - p1.y) == (p2.x - p1.x) * (p1.y - y))
146  ) {
147  // update the last point in this case, not to add a new one
148  p1.x = x;
149  p1.y = y;
151  lastFragmentLength = std::sqrt((float)(p1 - p2).hypot2());
153  return;
154  }
155  if (x == p1.x && y == p1.y)
156  return; //p1 == (x,y)
157  }
158 
159  // adding the new point
160  IntPoint p(x, y);
161  points.push_back(p);
162  lastFragmentLength = 0;
163 }
164 
165 
166 void IntegerContour2D::computeBoundary(std::vector<IntegerContour2D*>& boundary, AbstractBitmap& bitmap, std::vector<IntPoint>& border, BinaryMaskWriter& testedPixels, float level) {
167  BitmapProcessing::read<Kernels::ComputeBounds>(bitmap, boundary, border, testedPixels, level);
168 }
169 
170 
172  points.clear();
174 }
A very basic class for any image.
A sequence of integer-valued 2D points.
Definition: contours.h:33
static void computeBoundary(std::vector< IntegerContour2D * > &boundary, AbstractBitmap &bitmap, std::vector< IntPoint > &border, BinaryMaskWriter &testedPixels, float level=0.5f)
Discovers an area boundary in a bitmap following a level curve, starting from a given set of points.
Definition: contours.cpp:166
void clear()
Removes contour content.
Definition: contours.cpp:171
std::vector< IntPoint > points
Definition: contours.h:35
void addPoint(int x, int y)
Adds a new point to the end of the contour.
Definition: contours.cpp:137
unsigned char getValue() const
Returns 0..MAX_UNNORM_VALUE value at current position.
void goTo(int x, int y)
Changes current position.
A generic to write mask bitmap data lookup tables for masks values.
void putValue(unsigned char x)
Puts a properly scaled (0..MAX_UNNORM_VALUE) value at the current position.
static void process(AbstractBitmap &bitmap, std::vector< IntegerContour2D * > &boundary, std::vector< IntPoint > &border, BinaryMaskWriter &testedPixels, float level)
Definition: contours.cpp:29
Operations kernels.
Definition: basic_types.h:85
CustomPoint< numeric > max(const CustomPoint< numeric > &a, const CustomPoint< numeric > &b)
Definition: geometry.h:728
jobject jlong jint jint y
jobject jlong jint x
Beatmup::InternalBitmap * bitmap
Beatmup::IntPoint p((int) x,(int) y)