-
Notifications
You must be signed in to change notification settings - Fork 6
/
outline.cpp
133 lines (106 loc) · 3.34 KB
/
outline.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#include <cstdbool>
#include <algorithm>
#include "log.h"
#include "pixels.h"
#include "options.h"
#include "outline.h"
// The priority for which pixels to go to, search forward if no black yet
// or backward for white if first is black (see Outline::findEdge)
// 6 7 0
// 5 1
// 4 3 2
const std::array<Coord, 8> Outline::matrix = {{
Coord( 1, -1),
Coord( 1, 0),
Coord( 1, 1),
Coord( 0, 1),
Coord(-1, 1),
Coord(-1, 0),
Coord(-1, -1),
Coord( 0, -1)
}};
Outline::Outline(const Blobs& blobs, const Coord& point,
const int max_length)
:blobs(blobs)
{
// Current label so we only walk around this object
label = blobs.label(point);
if (label == Blobs::default_label)
{
log("can't outline object with default label");
return;
}
// Start one pixel above this first point (we wouldn't have been given this
// point if the pixel above it was black)
Coord position(point.x, point.y-1);
// A fail-safe
int iterations = 0;
// Walk the edge of the box
// Note: "break" when we're done, "return" gives up since this isn't a box
while (true)
{
// Find next pixel to go to
EdgePair edge = findEdge(position);
// We've gone everywhere
if (edge.index == -1)
break;
// Go to new position (note that edge.point will be position unless
// we had to retrace our steps a ways)
position = edge.point+matrix[edge.index];
path.push_back(position);
sortedpath.insert(position);
// Give up after we reach a certain size of object
++iterations;
if (iterations > max_length)
return;
}
// If we didn't return already, we found the points.
found = true;
}
// If we've been to pixel before, go back till we can go some place new.
EdgePair Outline::findEdge(const Coord& p) const
{
typedef std::vector<Coord>::size_type size_type;
int index = -1;
// Start at this point
Coord position = p;
// If that doesn't work, start at the last pixel
size_type path_index = (path.size()>0)?(path.size()-1):0;
// Keep going backwards until we find one with another option
while (true)
{
index = findIndex(position);
// We found an option!
if (index != -1)
break;
// We ran out of options
if (path_index == 0)
break;
// Go back one pixel
position = path[path_index];
--path_index;
}
return EdgePair(position, index);
}
// Loop through the matrix looking for the first black pixel with a white (not
// part of this object) pixel previous to it that we haven't been to. Return -1
// if there's no options (e.g. white pixel in middle of black ring).
int Outline::findIndex(const Coord& p) const
{
typedef std::array<Coord, 8>::size_type size_type;
int result = -1;
for (size_type i = 0; i < matrix.size(); ++i)
{
// Back one pixel with looping, i.e. 0-1 = 7
const int back = (i==0)?(matrix.size()-1):(i-1);
const Coord current = p+matrix[i];
const Coord previous = p+matrix[back];
if (blobs.label(current) == label && blobs.label(previous) != label &&
sortedpath.find(previous) == sortedpath.end())
{
result = back;
break;
}
}
return result;
}