44
55#include " precomp.hpp"
66#include < limits>
7- #include < vector>
87#include < utility>
8+ #include < vector>
99
1010namespace cv {
1111namespace 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.)
9896std::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}
0 commit comments