@@ -79,7 +79,7 @@ int longestColRunLength(const Mat& kernel)
79
79
return maxLen;
80
80
}
81
81
82
- std::vector<Point> findSeeds (const Mat& stNode, int rowDepth, int colDepth)
82
+ std::vector<Point> findP2RectCorners (const Mat& stNode, int rowDepth, int colDepth)
83
83
{
84
84
int rowOfst = 1 << rowDepth;
85
85
int colOfst = 1 << colDepth;
@@ -97,7 +97,7 @@ std::vector<Point> findSeeds(const Mat& stNode, int rowDepth, int colDepth)
97
97
if (row > 0 && stNode.at <uchar>(row - 1 , col) == 1
98
98
&& row + 1 < stNode.rows && stNode.at <uchar>(row + 1 , col) == 1 ) continue ;
99
99
100
- // zignore if neighboring block is white; will be alive in deeper table
100
+ // ignore if neighboring block is white
101
101
if (col + colOfst < stNode.cols && stNode.at <uchar>(row, col + colOfst) == 1 ) continue ;
102
102
if (col - colOfst >= 0 && stNode.at <uchar>(row, col - colOfst) == 1 ) continue ;
103
103
if (row + rowOfst < stNode.rows && stNode.at <uchar>(row + rowOfst, col) == 1 ) continue ;
@@ -109,43 +109,48 @@ std::vector<Point> findSeeds(const Mat& stNode, int rowDepth, int colDepth)
109
109
return p2Rects;
110
110
}
111
111
112
+ /*
113
+ * Find a set of power-2-rectangles to cover the kernel.
114
+ * power-2-rectangles is a rectangle whose height and width are both power of 2.
115
+ */
112
116
std::vector<std::vector<std::vector<Point>>> genPow2RectsToCoverKernel (
113
117
const Mat& kernel, int rowDepthLim, int colDepthLim)
114
118
{
115
119
CV_Assert (kernel.type () == CV_8UC1);
116
120
117
121
std::vector<std::vector<std::vector<Point>>> p2Rects;
118
- Mat stCache = kernel;
122
+ Mat stNodeCache = kernel;
119
123
for (int rowDepth = 0 ; rowDepth < rowDepthLim; rowDepth++)
120
124
{
121
- Mat st = stCache .clone ();
125
+ Mat stNode = stNodeCache .clone ();
122
126
p2Rects.emplace_back (std::vector<std::vector<Point>>());
123
127
for (int colDepth = 0 ; colDepth < colDepthLim; colDepth++)
124
128
{
125
- p2Rects[rowDepth].emplace_back (findSeeds (st , rowDepth, colDepth));
129
+ p2Rects[rowDepth].emplace_back (findP2RectCorners (stNode , rowDepth, colDepth));
126
130
int colStep = 1 << colDepth;
127
- if (st .cols - colStep < 0 ) break ;
128
- Rect s1 (0 , 0 , st .cols - colStep, st .rows );
129
- Rect s2 (colStep, 0 , st .cols - colStep, st .rows );
130
- cv::min (st (s1), st (s2), st );
131
+ if (stNode .cols - colStep < 0 ) break ;
132
+ Rect s1 (0 , 0 , stNode .cols - colStep, stNode .rows );
133
+ Rect s2 (colStep, 0 , stNode .cols - colStep, stNode .rows );
134
+ cv::min (stNode (s1), stNode (s2), stNode );
131
135
}
132
136
int rowStep = 1 << rowDepth;
133
- if (stCache .rows - rowStep < 0 ) break ;
134
- Rect s1 (0 , 0 , stCache .cols , stCache .rows - rowStep);
135
- Rect s2 (0 , rowStep, stCache .cols , stCache .rows - rowStep);
136
- cv::min (stCache (s1), stCache (s2), stCache );
137
+ if (stNodeCache .rows - rowStep < 0 ) break ;
138
+ Rect s1 (0 , 0 , stNodeCache .cols , stNodeCache .rows - rowStep);
139
+ Rect s2 (0 , rowStep, stNodeCache .cols , stNodeCache .rows - rowStep);
140
+ cv::min (stNodeCache (s1), stNodeCache (s2), stNodeCache );
137
141
}
138
142
139
- // todo: implement greedy algorithm to minimize the rectangle set covering the kernel.
140
-
141
143
return p2Rects;
142
144
}
143
145
144
146
Mat SolveRSAPGreedy (const Mat& initialMap)
145
147
{
146
148
/*
147
- * Solves the rectilinear steiner arborescence problem
149
+ * Solves the rectilinear steiner arborescence problem greedy.
148
150
* https://link.springer.com/article/10.1007/BF01758762
151
+ *
152
+ * Following implementation is O(n^3)-time algorithm
153
+ * which is different from the mothod proposed in the paper.
149
154
*/
150
155
CV_Assert (initialMap.type () == CV_8UC1);
151
156
std::vector<Point> pos;
@@ -194,9 +199,16 @@ Mat SolveRSAPGreedy(const Mat& initialMap)
194
199
return resMap;
195
200
}
196
201
197
- Mat planSparseTableConstr (
202
+ Mat sparseTableFillPlanning (
198
203
std::vector<std::vector<std::vector<Point>>> pow2Rects, int rowDepthLim, int colDepthLim)
199
204
{
205
+ /*
206
+ * Plan the order to fill the required 2d-sparse-table nodes.
207
+ * The type of returned mat is Vec2b.
208
+ * if path[dr][dc][0] == 1 then st[dr+1][dc] will be calculated from st[dr][dc].
209
+ * if path[dr][dc][1] == 1 then st[dr][dc+1] will be calculated from st[dr][dc].
210
+ */
211
+
200
212
// list up required sparse table nodes.
201
213
Mat stMap = Mat::zeros (rowDepthLim, colDepthLim, CV_8UC1);
202
214
for (int rd = 0 ; rd < rowDepthLim; rd++)
@@ -219,7 +231,6 @@ void morphDfs(int minmax, Mat& st, Mat& dst,
219
231
else cv::max (dst, st (rect), dst);
220
232
}
221
233
222
- // Fill col-direction first.
223
234
if (stPlan.at <Vec2b>(rowDepth, colDepth)[1 ] == 1 )
224
235
{
225
236
// col direction
@@ -258,7 +269,7 @@ void morphOp(Op minmax, InputArray _src, OutputArray _dst, InputArray kernel,
258
269
std::vector<std::vector<std::vector<Point>>> pow2Rects
259
270
= genPow2RectsToCoverKernel (_kernel, rowDepthLim, colDepthLim);
260
271
Mat stPlan
261
- = planSparseTableConstr (pow2Rects, rowDepthLim, colDepthLim);
272
+ = sparseTableFillPlanning (pow2Rects, rowDepthLim, colDepthLim);
262
273
263
274
Mat src = _src.getMat ();
264
275
_dst.create (_src.size (), _src.type ());
0 commit comments