OPAL (Object Oriented Parallel Accelerator Library) 2024.2
OPAL
Mask.cpp
Go to the documentation of this file.
5
6#include <filesystem>
7#include <iostream>
8#include <regex>
9#include <stack>
10#include <string>
11#include <tuple>
12#include <utility>
13#include <vector>
14
15namespace {
16 void updateCache(const std::vector<bool> &pixels, std::vector<int> &cache, int x, int width) {
17 const int height = cache.size();
18 for (int y = 0; y < height; ++ y) {
19 if (pixels[x + y * width]) {
20 ++ cache[y];
21 } else {
22 cache[y] = 0;
23 }
24 }
25 }
26}
27
28namespace mslang {
29 long Mask::computeArea(const Mask::IntPoint &ll, const Mask::IntPoint &ur) const {
30 if ((ur.x_m > ll.x_m) && (ur.y_m > ll.y_m))
31 return (ur.x_m - ll.x_m) * (ur.y_m - ll.y_m);
32
33 return 0;
34 }
35
36 std::pair<Mask::IntPoint, Mask::IntPoint> Mask::findMaximalRectangle(const std::vector<bool> &pixels,
37 int M, /* height */
38 int N /* width */) const {
39
40 // This algorithm was presented in
41 // http://www.drdobbs.com/database/the-maximal-rectangle-problem/184410529
42 // by David Vandevoorde, April 01, 1998
43
44 int bestArea = 0;
45 IntPoint bestLL(0, 0), bestUR(0,0);
46 std::vector<int> cache(M, 0);
47 std::stack<std::pair<int, int> > stack;
48 for (int x = N - 1; x >= 0; -- x) {
49 updateCache(pixels, cache, x, N);
50 int width = 0;
51 for (int y = 0; y < M; ++ y) {
52 if (cache[y] > width) {
53 stack.push(std::make_pair(y, width));
54 width = cache[y];
55 } else if (cache[y] < width) {
56 int y0, w0;
57 do {
58 std::tie(y0, w0) = stack.top();
59 stack.pop();
60 if (width * (y - y0) > bestArea) {
61 bestLL.x_m = x; bestLL.y_m = y0;
62 bestUR.x_m = x + width; bestUR.y_m = y;
63 bestArea = width * (y - y0);
64 }
65 width = w0;
66 } while (!stack.empty() && cache[y] < width);
67 width = cache[y];
68 if (width != 0) {
69 stack.push(std::make_pair(y0, width));
70 }
71 }
72 }
73
74 if (!stack.empty()) {
75 int y0, w0;
76 std::tie(y0, w0) = stack.top();
77 stack.pop();
78 if (width * (N - y0) > bestArea) {
79 bestLL.x_m = x; bestLL.y_m = y0;
80 bestUR.x_m = x + width; bestUR.y_m = N;
81 bestArea = width * (N - y0);
82 }
83 }
84 }
85
86 return std::make_pair(bestLL, bestUR);
87 }
88
89 std::vector<Mask::IntPixel_t> Mask::minimizeNumberOfRectangles(std::vector<bool> pixels,
90 int M,/* height */
91 int N /* width */)
92 {
93 std::vector<IntPixel_t> rectangles;
94
95 long maxArea = 0;
96 while (true) {
97 IntPixel_t pix = findMaximalRectangle(pixels, M, N);
98 long area = computeArea(pix.first, pix.second);
99 if (area > maxArea) maxArea = area;
100 if (area <= 1) {
101 break;
102 }
103
104 rectangles.push_back(pix);
105
106 for (int y = pix.first.y_m; y < pix.second.y_m; ++ y) {
107 int idx = y * N + pix.first.x_m;
108 for (int x = pix.first.x_m; x < pix.second.x_m; ++ x, ++ idx) {
109 pixels[idx] = false;
110 }
111 }
112 }
113 int idx = 0;
114 for (int y = 0; y < M; ++ y) {
115 for (int x = 0; x < N; ++ x, ++idx) {
116 if (pixels[idx]) {
117 IntPoint ll(x, y);
118 IntPoint ur(x, y);
119 rectangles.push_back(IntPixel_t(ll, ur));
120 }
121 }
122 }
123
124 return rectangles;
125 }
126
128 Mask *pixmap = static_cast<Mask*>(fun);
129
130 ArgumentExtractor arguments(std::string(it, end));
131 std::string filename = arguments.get(0);
132 if (filename[0] == '\'' && filename.back() == '\'') {
133 filename = filename.substr(1, filename.length() - 2);
134 }
135
136 if (!std::filesystem::exists(filename)) {
137 ERRORMSG("file '" << filename << "' doesn't exists" << endl);
138 return false;
139 }
140
141 PortableBitmapReader reader(filename);
142 int width = reader.getWidth();
143 int height = reader.getHeight();
144
145 double pixel_width;
146 double pixel_height;
147 try {
148 pixel_width = parseMathExpression(arguments.get(1)) / width;
149 pixel_height = parseMathExpression(arguments.get(2)) / height;
150 } catch (std::runtime_error &e) {
151 std::cout << e.what() << std::endl;
152 return false;
153 }
154
155 if (pixel_width < 0.0) {
156 std::cout << "Mask: a negative width provided '"
157 << arguments.get(0) << " = " << pixel_width * width << "'"
158 << std::endl;
159 return false;
160 }
161
162 if (pixel_height < 0.0) {
163 std::cout << "Mask: a negative height provided '"
164 << arguments.get(1) << " = " << pixel_height * height << "'"
165 << std::endl;
166 return false;
167 }
168
169 auto maxRect = pixmap->minimizeNumberOfRectangles(reader.getPixels(), height, width);
170 for (const IntPixel_t &pix: maxRect) {
171 const IntPoint &ll = pix.first;
172 const IntPoint &ur = pix.second;
173
174 Rectangle rect;
175 rect.width_m = (ur.x_m - ll.x_m) * pixel_width;
176 rect.height_m = (ur.y_m - ll.y_m) * pixel_height;
177
178 double midX = 0.5 * (ur.x_m + ll.x_m);
179 double midY = 0.5 * (ur.y_m + ll.y_m);
180 rect.trafo_m = AffineTransformation(Vector_t({1, 0, (0.5 * width - midX) * pixel_width}),
181 Vector_t({0, 1, (midY - 0.5 * height) * pixel_height}));
182
183 pixmap->pixels_m.push_back(rect);
184 pixmap->pixels_m.back().computeBoundingBox();
185 }
186
187 it += (arguments.getLengthConsumed() + 1);
188
189 return true;
190 }
191
192 void Mask::print(int ident) {
193 for (auto pix: pixels_m) pix.print(ident);
194 }
195
196 void Mask::apply(std::vector<std::shared_ptr<Base> > &bfuncs) {
197 for (auto pix: pixels_m) pix.apply(bfuncs);
198 }
199}
PartBunchBase< T, Dim >::ConstIterator end(PartBunchBase< T, Dim > const &bunch)
Inform & endl(Inform &inf)
Definition Inform.cpp:42
#define ERRORMSG(msg)
Definition IpplInfo.h:350
double parseMathExpression(const std::string &str)
Definition matheval.cpp:4
std::string::iterator iterator
Definition MSLang.h:13
AffineTransformation trafo_m
Definition MSLang.h:38
std::string get(unsigned int i) const
unsigned int getLengthConsumed() const
virtual void apply(std::vector< std::shared_ptr< Base > > &bfuncs)
Definition Mask.cpp:196
virtual void print(int ident)
Definition Mask.cpp:192
static bool parse_detail(iterator &it, const iterator &end, Function *&fun)
Definition Mask.cpp:127
std::pair< IntPoint, IntPoint > IntPixel_t
Definition Mask.h:31
long computeArea(const IntPoint &ll, const IntPoint &ur) const
Definition Mask.cpp:29
std::pair< IntPoint, IntPoint > findMaximalRectangle(const std::vector< bool > &pixels, int height, int width) const
Definition Mask.cpp:36
std::vector< Rectangle > pixels_m
Definition Mask.h:17
std::vector< IntPixel_t > minimizeNumberOfRectangles(std::vector< bool > pixels, int height, int width)
Definition Mask.cpp:89
std::vector< bool > getPixels() const
unsigned int getWidth() const
unsigned int getHeight() const
Vektor< double, 3 > Vector_t
Definition Vektor.h:6