Skip to content

Commit 1714254

Browse files
committed
Fix segfault due to invalid masks generation. Fixes nmoehrle#125.
Until now, it was possible that a mask with a 255 in its border was generated, later failing the `valid_mask` assertions, or, if assertions are disabled by the build, segementation faults due to invalid memory accesses. See the example in the added comment for a condition where this could happen. The key insight is that if a point lay exactly on the "border" between two pixels, say between pixel N and N+1, it counted as occupying pixel N+1. So the triangle { (1,1), (1,2), (2,1) } in a 3x3 image would result in mask 64 64 64 64 255 255 64 255 64 (notice the triangle of 255s), instead of the correct mask 64 64 64 64 255 64 64 64 64 This commit fixes it by adding the condition that the last `x = width-1` and `y = height-1` must not count as `inside` the triangle. It also improves related assertions in a few places.
1 parent 2fa6d14 commit 1714254

File tree

2 files changed

+24
-2
lines changed

2 files changed

+24
-2
lines changed

libs/tex/poisson_blending.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@ typedef Eigen::SparseMatrix<float> SpMat;
2020

2121
math::Vec3f simple_laplacian(int i, mve::FloatImage::ConstPtr img){
2222
const int width = img->width();
23-
assert(i > width + 1 && i < img->get_pixel_amount() - width -1);
23+
// Check it's not in the top/bottom border (`texture_patch_border = 1`).
24+
assert(i > width && i < img->get_pixel_amount() - width);
25+
// Check it's not in the left/right border (`texture_patch_border = 1`).
26+
assert(i % width != 0 && i % width != width-1);
2427

2528
return -4.0f * math::Vec3f(&img->at(i, 0))
2629
+ math::Vec3f(&img->at(i - width, 0))

libs/tex/texture_patch.cpp

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,28 @@ TexturePatch::adjust_colors(std::vector<math::Vec3f> const & adjust_values) {
6767
for (int x = min_x; x < max_x; ++x) {
6868

6969
math::Vec3f bcoords = tri.get_barycentric_coords(x, y);
70-
bool inside = bcoords.minimum() >= 0.0f;
70+
// The point (x, y) is inside the triangle if all of its
71+
// barycentric coordinates are positive.
72+
// Further, we need to check that (x, y) does not touch the
73+
// upper `texture_patch_border` (width-1 and height-1).
74+
// This isn't necessary for the lower boarders.
75+
// Example:
76+
// Consider the triangle { (0,0), (0,1), (1,0) }
77+
// in a 1x1 pixel image. With 1-pixels borders added around it
78+
// it becomes the triangle { (1,1), (1,2), (2,1) }
79+
// in a 3x3 pixel image.
80+
// The lower borders (rows x=0 and y=0) will be free as expected
81+
// because no point has these coordinates.
82+
// But the upper border x=2 is "just touched" by point (2,1),
83+
// so it would be marked as occupied (and texture borders are
84+
// intended to be not occupied).
85+
// Thus we must exclude them explicitly in the `inside`
86+
// condition.
87+
bool inside = bcoords.minimum() >= 0.0f
88+
&& x != get_width() - 1 && y != get_height() - 1;
7189
if (inside) {
7290
assert(x != 0 && y != 0);
91+
assert(x != get_width() - 1 && y != get_height() - 1);
7392
for (int c = 0; c < 3; ++c) {
7493
iadjust_values->at(x, y, c) = math::interpolate(
7594
adjust_values[i][c], adjust_values[i + 1][c], adjust_values[i + 2][c],

0 commit comments

Comments
 (0)