Code indexing in gitaly is broken and leads to code not being visible to the user. We work on the issue with highest priority.

Skip to content
Snippets Groups Projects
Commit d613add4 authored by kraus's avatar kraus
Browse files

reducing number of 'pixels' in Mask to reduce compute time and memory usage; Implements #256

parent 5efa7eff
No related branches found
No related tags found
No related merge requests found
...@@ -7,6 +7,116 @@ ...@@ -7,6 +7,116 @@
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
namespace mslang { namespace mslang {
void Mask::updateCache(const std::vector<bool> &pixels, std::vector<unsigned int> &cache, unsigned int y) const {
const unsigned int M = cache.size();
unsigned int idx = y * M;
for (unsigned int x = 0; x < M; ++ x, ++ idx) {
if (pixels[idx]) {
++ cache[x];
} else {
cache[x] = 0;
}
}
}
unsigned int Mask::computeArea(const Mask::IntPoint &ll, const Mask::IntPoint &ur) const {
if ((ur.x_m > ll.x_m) && (ur.y_m > ll.y_m))
return (ur.x_m - ll.x_m) * (ur.y_m - ll.y_m);
return 0;
}
std::pair<Mask::IntPoint, Mask::IntPoint> Mask::findMaximalRectangle(const std::vector<bool> &pixels,
unsigned int N, /* height */
unsigned int M /* width */) const {
// This algorithm was presented in
// http://www.drdobbs.com/database/the-maximal-rectangle-problem/184410529
// by David Vandevoorde, April 01, 1998
unsigned int bestArea = 0;
IntPoint bestLL(0, 0), bestUR(0,0);
std::vector<unsigned int> cache(M, 0);
std::stack<std::pair<unsigned int, unsigned int> > stack;
for (unsigned int y = N - 1; y + 1 > 0; -- y) {
updateCache(pixels, cache, y);
unsigned int height = 0;
for (unsigned int x = 0; x < M; ++ x) {
if (cache[x] > height) {
stack.push(std::make_pair(x, height));
height = cache[x];
} else if (cache[x] < height) {
std::pair<unsigned int, unsigned int> tmp;
do {
tmp = stack.top();
stack.pop();
if (x > tmp.first && height * (x - tmp.first) > bestArea) {
bestLL.x_m = tmp.first; bestLL.y_m = y;
bestUR.x_m = x; bestUR.y_m = y + height;
bestArea = height * (x - tmp.first);
}
height = tmp.second;
} while (stack.size() > 0 && cache[x] < height);
height = cache[x];
if (height != 0) {
stack.push(std::make_pair(tmp.first, height));
}
}
}
if (stack.size() > 0) {
std::pair<unsigned int, unsigned int> tmp = stack.top();
stack.pop();
if (M > tmp.first && height * (M - tmp.first) > bestArea) {
bestLL.x_m = tmp.first; bestLL.y_m = y;
bestUR.x_m = M; bestUR.y_m = y + height;
bestArea = height * (M - tmp.first);
}
}
}
return std::make_pair(bestLL, bestUR);
}
std::vector<Mask::IntPixel_t> Mask::minimizeNumberOfRectangles(std::vector<bool> pixels,
unsigned int N,/* height */
unsigned int M /* width */)
{
std::vector<IntPixel_t> rectangles;
unsigned int maxArea = 0;
while (true) {
IntPixel_t pix = findMaximalRectangle(pixels, N, M);
unsigned int area = computeArea(pix.first, pix.second);
if (area > maxArea) maxArea = area;
if (1000 * area < maxArea || area <= 1) {
break;
}
rectangles.push_back(pix);
for (int y = pix.first.y_m; y < pix.second.y_m; ++ y) {
unsigned int idx = y * M + pix.first.x_m;
for (int x = pix.first.x_m; x < pix.second.x_m; ++ x, ++ idx) {
pixels[idx] = false;
}
}
}
unsigned int idx = 0;
for (unsigned int y = 0; y < N; ++ y) {
for (unsigned int x = 0; x < M; ++ x, ++idx) {
if (pixels[idx]) {
IntPoint ll(x, y);
IntPoint ur(x + 1, y + 1);
rectangles.push_back(IntPixel_t(ll, ur));
}
}
}
return rectangles;
}
bool Mask::parse_detail(iterator &it, const iterator &end, Function* &fun) { bool Mask::parse_detail(iterator &it, const iterator &end, Function* &fun) {
Mask *pixmap = static_cast<Mask*>(fun); Mask *pixmap = static_cast<Mask*>(fun);
...@@ -49,19 +159,23 @@ namespace mslang { ...@@ -49,19 +159,23 @@ namespace mslang {
return false; return false;
} }
for (unsigned int i = 0; i < height; ++ i) { auto maxRect = pixmap->minimizeNumberOfRectangles(reader.getPixels(), height, width);
for (unsigned int j = 0; j < width; ++ j) {
if (reader.isBlack(i, j)) { for (const IntPixel_t &pix: maxRect) {
Rectangle rect; const IntPoint &ll = pix.first;
rect.width_m = pixel_width; const IntPoint &ur = pix.second;
rect.height_m = pixel_height;
rect.trafo_m = AffineTransformation(Vector_t(1, 0, (0.5 * width - j) * pixel_width), Rectangle rect;
Vector_t(0, 1, (i - 0.5 * height) * pixel_height)); rect.width_m = (ur.x_m - ll.x_m) * pixel_width;
rect.height_m = (ur.y_m - ll.y_m) * pixel_height;
pixmap->pixels_m.push_back(rect);
pixmap->pixels_m.back().computeBoundingBox(); double midX = 0.5 * (ur.x_m + ll.x_m);
} double midY = 0.5 * (ur.y_m + ll.y_m);
} rect.trafo_m = AffineTransformation(Vector_t(1, 0, (0.5 * width - midX) * pixel_width),
Vector_t(0, 1, (midY - 0.5 * height) * pixel_height));
pixmap->pixels_m.push_back(rect);
pixmap->pixels_m.back().computeBoundingBox();
} }
it += (arguments.getLengthConsumed() + 1); it += (arguments.getLengthConsumed() + 1);
......
...@@ -11,6 +11,32 @@ namespace mslang { ...@@ -11,6 +11,32 @@ namespace mslang {
virtual void apply(std::vector<std::shared_ptr<Base> > &bfuncs); virtual void apply(std::vector<std::shared_ptr<Base> > &bfuncs);
std::vector<Rectangle> pixels_m; std::vector<Rectangle> pixels_m;
private:
struct IntPoint {
IntPoint(int x, int y):
x_m(x),
y_m(y)
{ }
int x_m;
int y_m;
};
typedef std::pair<IntPoint, IntPoint> IntPixel_t;
std::vector<IntPixel_t> minimizeNumberOfRectangles(std::vector<bool> pixels,
unsigned int height,
unsigned int width);
std::pair<IntPoint, IntPoint> findMaximalRectangle(const std::vector<bool> &pixels,
unsigned int height,
unsigned int width) const;
unsigned int computeArea(const IntPoint &ll, const IntPoint &ur) const;
void updateCache(const std::vector<bool> &pixels, std::vector<unsigned int> &cache, unsigned int y) const;
}; };
} }
......
...@@ -15,6 +15,7 @@ public: ...@@ -15,6 +15,7 @@ public:
unsigned int getHeight() const; unsigned int getHeight() const;
bool isBlack(unsigned int i, unsigned int j) const; bool isBlack(unsigned int i, unsigned int j) const;
std::vector<bool> getPixels() const;
void print(std::ostream &out) const; void print(std::ostream &out) const;
private: private:
...@@ -53,6 +54,11 @@ bool PortableBitmapReader::isBlack(unsigned int i, unsigned int j) const { ...@@ -53,6 +54,11 @@ bool PortableBitmapReader::isBlack(unsigned int i, unsigned int j) const {
return pixels_m[getIdx(i, j)]; return pixels_m[getIdx(i, j)];
} }
inline
std::vector<bool> PortableBitmapReader::getPixels() const {
return pixels_m;
}
inline inline
unsigned int PortableBitmapReader::getIdx(unsigned int h, unsigned int w) const { unsigned int PortableBitmapReader::getIdx(unsigned int h, unsigned int w) const {
if (h >= height_m || w >= width_m) throw OpalException("PortableBitmapReader::getIdx", if (h >= height_m || w >= width_m) throw OpalException("PortableBitmapReader::getIdx",
......
  • snuverink_j @snuverink_j ·
    Developer

    This commit probably broke the Mask regression test: http://amas.web.psi.ch/opal/regressionTests/master/results_2018-11-18.xml

  • Author Developer

    Yes this is very probable: there was a bug in the code before which I noticed when testing the changes. I'll test this hypothesis.

0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment