Skip to content

Commit bd20e2a

Browse files
committed
DFSで構築するように変更
1 parent c20593a commit bd20e2a

File tree

3 files changed

+116
-167
lines changed

3 files changed

+116
-167
lines changed

modules/ximgproc/include/opencv2/ximgproc/sparse_table_morphology.hpp

Lines changed: 5 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -95,59 +95,26 @@ static inline Point normalizeAnchor(Point anchor, Size ksize)
9595
return anchor;
9696
}
9797

98-
enum Dim
99-
{
100-
Col, Row
101-
};
102-
10398
enum Op
10499
{
105100
Min, Max
106101
};
107102

108-
enum StStrategy
109-
{
110-
Faster,
111-
SaveMemory
112-
};
113-
114-
enum QueryType
115-
{
116-
Stuck,
117-
Pop,
118-
Fill,
119-
};
120-
121-
struct StStep
122-
{
123-
StStep(QueryType _qType, int dimR, int dimC, Dim _ax, std::vector<Point> _points)
124-
{
125-
qType = _qType;
126-
dimRow = dimR;
127-
dimCol = dimC;
128-
ax = _ax;
129-
points = _points;
130-
}
131-
QueryType qType;
132-
int dimRow;
133-
int dimCol;
134-
Dim ax;
135-
std::vector<Point> points;
136-
};
137-
138103
/*
139104
* Find a set of power-2-rectangles to cover the kernel.
140105
* power-2-rectangles is a rectangle whose height and width are both power of 2.
106+
* (The width and height values of returned rects ​​are the log2 of the actual values.)
141107
*/
142108
CV_EXPORTS_W std::vector<std::vector<std::vector<Point>>> genPow2RectsToCoverKernel(
143109
const Mat& kernel, int rowLim, int colLim);
144110
//
145111
/*
146112
* Plan the order to fill the required sparse table nodes.
113+
* returnd Mat type is Vec2b.
114+
*
147115
*/
148-
CV_EXPORTS_W std::vector<StStep> planSparseTableConstr(
149-
std::vector<std::vector<std::vector<Point>>> stNodeMap, int rowLim, int colLim,
150-
StStrategy strategy = Faster);
116+
CV_EXPORTS_W Mat planSparseTableConstr(
117+
std::vector<std::vector<std::vector<Point>>> stNodeMap, int rowLim, int colLim);
151118

152119
CV_EXPORTS_W int log2(int n);
153120
CV_EXPORTS_W int longestRowRunLength(const Mat& kernel);

modules/ximgproc/src/sparse_table_morphology.cpp

Lines changed: 93 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44

55
#include "precomp.hpp"
66
#include <limits>
7-
#include <vector>
87
#include <utility>
8+
#include <vector>
99

1010
namespace cv {
1111
namespace stMorph {
@@ -93,8 +93,6 @@ std::vector<Point> findSeeds(const Mat& stNode, int rowDepth, int colDepth)
9393
return p2Rects;
9494
}
9595

96-
// Generate list of rectangles whose width and height are power of 2.
97-
// (The width and height values of returned rects ​​are the log2 of the actual values.)
9896
std::vector<std::vector<std::vector<Point>>> genPow2RectsToCoverKernel(
9997
const Mat& kernel, int rowDepthLim, int colDepthLim)
10098
{
@@ -127,85 +125,107 @@ std::vector<std::vector<std::vector<Point>>> genPow2RectsToCoverKernel(
127125
return p2Rects;
128126
}
129127

130-
std::vector<StStep> planSparseTableConstr(
131-
std::vector<std::vector<std::vector<Point>>> pow2Rects, int rowDepthLim, int colDepthLim,
132-
StStrategy strategy)
128+
Mat SolveRSAPGreedy(const Mat& initialMap)
133129
{
134-
// list up required sparse table nodes.
135-
std::vector<std::vector<bool>> sparseMatMap(rowDepthLim, std::vector<bool>(colDepthLim, false));
136-
for (int r = 0; r < pow2Rects.size(); r++)
137-
{
138-
for (int c = 0; c < pow2Rects[r].size(); c++)
139-
{
140-
if (pow2Rects[r][c].size() > 0) sparseMatMap[r][c] = true;
141-
}
142-
}
143-
sparseMatMap[0][0] = true;
144-
145-
switch (strategy)
146-
{
147-
case Faster:
130+
/*
131+
* Solves the rectilinear steiner arborescence problem
132+
* https://link.springer.com/article/10.1007/BF01758762
133+
*/
134+
CV_Assert(initialMap.type() == CV_8UC1);
135+
std::vector<Point> pos;
136+
for (int r = 0; r < initialMap.rows; r++)
137+
for (int c = 0; c < initialMap.cols; c++)
138+
if (initialMap.at<uchar>(r, c) == 1) pos.emplace_back(c, r);
139+
Mat resMap = Mat::zeros(initialMap.size(), CV_8UC2);
140+
141+
while (pos.size() > 1)
148142
{
149-
/*
150-
*
151-
* AtCoder: https://atcoder.jp/contests/ahc037/tasks/ahc037_a
152-
*
153-
* The rectilinear steiner arborescence problem
154-
* https://link.springer.com/article/10.1007/BF01758762
155-
*
156-
*/
157-
std::vector<Point> pos;
158-
for (int r = 0; r < sparseMatMap.size(); r++)
159-
for (int c = 0; c < sparseMatMap[r].size(); c++)
160-
if (sparseMatMap[r][c]) pos.emplace_back(c, r);
161-
std::vector<StStep> plan;
162-
while (pos.size() > 1)
143+
int maxCost = -1;
144+
int maxI = 0;
145+
int maxJ = 0;
146+
int maxX = 0;
147+
int maxY = 0;
148+
for (int i = 0; i < pos.size(); i++)
163149
{
164-
int maxCost = -1;
165-
int maxI = 0;
166-
int maxJ = 0;
167-
int maxX = 0;
168-
int maxY = 0;
169-
for (int i = 0; i < pos.size(); i++)
150+
for (int j = i + 1; j < pos.size(); j++)
170151
{
171-
for (int j = i + 1; j < pos.size(); j++)
152+
int _x = std::min(pos[i].x, pos[j].x);
153+
int _y = std::min(pos[i].y, pos[j].y);
154+
int cost = _x + _y;
155+
if (maxCost < cost)
172156
{
173-
int _x = std::min(pos[i].x, pos[j].x);
174-
int _y = std::min(pos[i].y, pos[j].y);
175-
int cost = _x + _y;
176-
if (maxCost < cost)
177-
{
178-
maxCost = cost;
179-
maxI = i;
180-
maxJ = j;
181-
maxX = _x;
182-
maxY = _y;
183-
}
157+
maxCost = cost;
158+
maxI = i;
159+
maxJ = j;
160+
maxX = _x;
161+
maxY = _y;
184162
}
185163
}
186-
for (int col = pos[maxI].x - 1; col >= maxX; col--)
187-
plan.emplace_back(Fill, pos[maxI].y, col, Dim::Col, pow2Rects[pos[maxI].y][col]);
188-
for (int row = pos[maxI].y - 1; row >= maxY; row--)
189-
plan.emplace_back(Fill, row, maxX, Dim::Row, pow2Rects[row][maxX]);
190-
for (int col = pos[maxJ].x - 1; col >= maxX; col--)
191-
plan.emplace_back(Fill, pos[maxJ].y, col, Dim::Col, pow2Rects[pos[maxJ].y][col]);
192-
for (int row = pos[maxJ].y - 1; row >= maxY; row--)
193-
plan.emplace_back(Fill, row, maxX, Dim::Row, pow2Rects[row][maxX]);
194-
195-
pos[maxI] = Point(maxX, maxY);
196-
swap(pos[maxJ], pos[pos.size() - 1]);
197-
pos.pop_back();
198164
}
165+
for (int col = pos[maxI].x - 1; col >= maxX; col--)
166+
resMap.at<Vec2b>(pos[maxI].y, col)[1] = 1;
167+
for (int row = pos[maxI].y - 1; row >= maxY; row--)
168+
resMap.at<Vec2b>(row, maxX)[0] = 1;
169+
for (int col = pos[maxJ].x - 1; col >= maxX; col--)
170+
resMap.at<Vec2b>(pos[maxJ].y, col)[1] = 1;
171+
for (int row = pos[maxJ].y - 1; row >= maxY; row--)
172+
resMap.at<Vec2b>(row, maxX)[0] = 1;
173+
174+
pos[maxI] = Point(maxX, maxY);
175+
swap(pos[maxJ], pos[pos.size() - 1]);
176+
pos.pop_back();
177+
}
178+
return resMap;
179+
}
199180

200-
reverse(plan.begin(), plan.end());
201-
return plan;
181+
Mat planSparseTableConstr(
182+
std::vector<std::vector<std::vector<Point>>> pow2Rects, int rowDepthLim, int colDepthLim)
183+
{
184+
// list up required sparse table nodes.
185+
Mat stMap = Mat::zeros(rowDepthLim, colDepthLim, CV_8UC1);
186+
for (int rd = 0; rd < rowDepthLim; rd++)
187+
for (int cd = 0; cd < colDepthLim; cd++)
188+
if (pow2Rects[rd][cd].size() > 0)
189+
stMap.at<uchar>(rd, cd) = 1;
190+
stMap.at<uchar>(0, 0) = 1;
191+
Mat path = SolveRSAPGreedy(stMap);
192+
return path;
193+
}
194+
195+
void morphDfs(int minmax, Mat& st, Mat& dst,
196+
std::vector<std::vector<std::vector<Point>>> row2Rects, const Mat& stPlan,
197+
int rowDepth, int colDepth)
198+
{
199+
for (Point p : row2Rects[rowDepth][colDepth])
200+
{
201+
Rect rect(p, dst.size());
202+
if (minmax == Op::Min) cv::min(dst, st(rect), dst);
203+
else cv::max(dst, st(rect), dst);
202204
}
203-
case StStrategy::SaveMemory:
205+
206+
// Fill col-direction first.
207+
if (stPlan.at<Vec2b>(rowDepth, colDepth)[1] == 1)
204208
{
205-
// todo: implement.
206-
std::vector<StStep> plan;
207-
return plan;
209+
// col direction
210+
Mat st2 = st;
211+
int ofs = 1 << colDepth;
212+
Rect rect1(0, 0, st2.cols - ofs, st2.rows);
213+
Rect rect2(ofs, 0, st2.cols - ofs, st2.rows);
214+
215+
if (minmax == Op::Min) cv::min(st2(rect1), st2(rect2), st2);
216+
else cv::max(st2(rect1), st2(rect2), st2);
217+
morphDfs(minmax, st2, dst, row2Rects, stPlan, rowDepth, colDepth + 1);
208218
}
219+
if (stPlan.at<Vec2b>(rowDepth, colDepth)[0] == 1)
220+
{
221+
// row direction
222+
int ofs = 1 << rowDepth;
223+
Rect rect1(0, 0, st.cols, st.rows - ofs);
224+
Rect rect2(0, ofs, st.cols, st.rows - ofs);
225+
226+
if (minmax == Op::Min) cv::min(st(rect1), st(rect2), st);
227+
else cv::max(st(rect1), st(rect2), st);
228+
morphDfs(minmax, st, dst, row2Rects, stPlan, rowDepth + 1, colDepth);
209229
}
210230
}
211231

@@ -221,8 +241,8 @@ void morphOp(Op minmax, InputArray _src, OutputArray _dst, InputArray kernel,
221241
int colDepthLim = log2(longestColRunLength(_kernel)) + 1;
222242
std::vector<std::vector<std::vector<Point>>> pow2Rects
223243
= genPow2RectsToCoverKernel(_kernel, rowDepthLim, colDepthLim);
224-
std::vector<StStep> stPlan
225-
= planSparseTableConstr(pow2Rects, rowDepthLim, colDepthLim, Faster);
244+
Mat stPlan
245+
= planSparseTableConstr(pow2Rects, rowDepthLim, colDepthLim);
226246

227247
Mat src = _src.getMat();
228248
_dst.create(_src.size(), _src.type());
@@ -239,53 +259,8 @@ void morphOp(Op minmax, InputArray _src, OutputArray _dst, InputArray kernel,
239259
anchor.y, _kernel.cols - 1 - anchor.y,
240260
anchor.x, _kernel.rows - 1 - anchor.x,
241261
borderType, bV);
242-
243262
dst.setTo(nil);
244-
245-
// TODO: keep only needed memories.
246-
std::vector<std::vector<Mat>> st(rowDepthLim, std::vector<Mat>(colDepthLim));
247-
st[0][0] = expandedSrc;
248-
for (int i = 0; i < stPlan.size(); i++)
249-
{
250-
StStep step = stPlan[i];
251-
Mat& curr = st[step.dimRow][step.dimCol];
252-
Mat* dst1;
253-
int ofsX = 0, ofsY = 0;
254-
if (step.ax == Dim::Col)
255-
{
256-
ofsX = 1 << step.dimCol;
257-
dst1 = &st[step.dimRow][step.dimCol + 1];
258-
}
259-
else
260-
{
261-
ofsY = 1 << step.dimRow;
262-
dst1 = &st[step.dimRow + 1][step.dimCol];
263-
}
264-
int width = curr.cols - ofsX;
265-
int height = curr.rows - ofsY;
266-
Mat& src1 = st[step.dimRow][step.dimCol](Rect(0, 0, width, height));
267-
Mat& src2 = st[step.dimRow][step.dimCol](Rect(ofsX, ofsY, width, height));
268-
dst1->create(height, width, curr.type());
269-
if (minmax == Op::Min) cv::min(src1, src2, *dst1);
270-
else cv::max(src1, src2, *dst1);
271-
}
272-
273-
// result constructioin
274-
for (int r = 0; r < pow2Rects.size(); r++)
275-
{
276-
for (int c = 0; c < pow2Rects[r].size(); c++)
277-
{
278-
for (Point p : pow2Rects[r][c])
279-
{
280-
Rect rect(p, Size(1 << c, 1 << r));
281-
Rect srcRect(p, dst.size());
282-
Mat& srcMat = st[r][c](srcRect);
283-
if (minmax == Op::Min) cv::min(dst, srcMat, dst);
284-
else cv::max(dst, srcMat, dst);
285-
}
286-
}
287-
}
288-
263+
morphDfs(minmax, expandedSrc, dst, pow2Rects, stPlan, 0, 0);
289264
src = dst;
290265
} while (--iterations > 0);
291266
}

modules/ximgproc/test/test_sparse_table_morphology.cpp

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ TEST(ximgproc_StMorph_private, feature_P2RCov_visualize) {
287287
#pragma region planning
288288

289289
void VisualizePlanning(
290-
std::vector<std::vector<std::vector<Point>>> map, std::vector<stMorph::StStep> res)
290+
std::vector<std::vector<std::vector<Point>>> map, Mat res)
291291
{
292292
int g = 30;
293293
int r = map.size();
@@ -302,16 +302,23 @@ void VisualizePlanning(
302302
cv::rectangle(m, nodeRect, Scalar(20, 20, 255), -1);
303303
}
304304
}
305-
for (int i = 0; i < res.size(); i++)
305+
for (int r = 0; r < res.rows; r++)
306306
{
307-
auto edge = res[i];
308-
Point sp(edge.dimCol * g + g / 2, edge.dimRow * g + g / 2);
309-
Point ep;
310-
if (edge.ax == stMorph::Dim::Row)
311-
ep = Point(edge.dimCol * g + g / 2, (edge.dimRow + 1) * g + g / 2);
312-
else
313-
ep = Point((edge.dimCol + 1) * g + g / 2, edge.dimRow * g + g / 2);
314-
cv::line(m, sp, ep, Scalar(100, 100, 100), 2);
307+
for (int c = 0; c < res.cols; c++)
308+
{
309+
Vec2b p = res.at<Vec2b>(r, c);
310+
Point sp(c * g + g / 2, r * g + g / 2);
311+
if (p[0] == 1)
312+
{
313+
Point ep = Point(c * g + g / 2, (r + 1) * g + g / 2);
314+
cv::line(m, sp, ep, Scalar(100, 100, 100), 2);
315+
}
316+
if (p[1] == 1)
317+
{
318+
Point ep = Point((c + 1) *g + g / 2, r * g + g / 2);
319+
cv::line(m, sp, ep, Scalar(100, 100, 100), 2);
320+
}
321+
}
315322
}
316323
#if 0
317324
imshow("Map", m);
@@ -335,7 +342,7 @@ void feture_planning(const Mat& mat)
335342
}
336343
}
337344

338-
auto r = stMorph::planSparseTableConstr(map, mat.rows, mat.cols, stMorph::StStrategy::Faster);
345+
auto r = stMorph::planSparseTableConstr(map, mat.rows, mat.cols);
339346
VisualizePlanning(map, r);
340347
}
341348
TEST(ximgproc_StMorph_private, planning1) { feture_planning(knAsymm()); }

0 commit comments

Comments
 (0)