Skip to content

Commit a49323b

Browse files
committed
部分をメソッドごとに分割、不要なMATのメモリ確保を削減、スパーステーブル作成前に2冪長方形に分ける方式に変更
1 parent 815b125 commit a49323b

File tree

2 files changed

+193
-151
lines changed

2 files changed

+193
-151
lines changed

modules/ximgproc/src/sparse_table_morphology.cpp

Lines changed: 177 additions & 147 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737
#include <math.h>
3838
#include <vector>
3939
#include <iostream>
40+
#include<stack>
41+
#include<algorithm>
4042

4143
namespace cv {
4244
namespace ximgproc {
@@ -53,6 +55,133 @@ static inline Point normalizeAnchor(Point anchor, Size ksize)
5355
return anchor;
5456
}
5557

58+
static std::vector<Rect> GetCoveringRectangles(InputArray _kernel)
59+
{
60+
std::vector<Rect> rects;
61+
Mat kernel = _kernel.getMat();
62+
int kCount = 0;
63+
64+
// 行ごとで四角を作るだけの実装
65+
for (int row = 0; row < kernel.rows; row++)
66+
{
67+
uchar pre = 0;
68+
for (int col = 0; col < kernel.cols; col++)
69+
{
70+
if (pre == 1 && kernel.ptr(row)[col] == 0)
71+
{
72+
rects[kCount].width = col - rects[kCount].x;
73+
kCount++;
74+
}
75+
if (pre == 0 && kernel.ptr(row)[col] == 1)
76+
{
77+
rects.emplace_back(col, row, 0, 1);
78+
}
79+
pre = kernel.ptr(row)[col];
80+
}
81+
if (pre == 1)
82+
{
83+
rects[kCount].width = kernel.cols - rects[kCount].x;
84+
kCount++;
85+
}
86+
}
87+
return rects;
88+
}
89+
90+
enum Dim
91+
{
92+
Col, Row
93+
};
94+
95+
struct StStep
96+
{
97+
StStep(int dimR, int dimC, Dim _ax)
98+
{
99+
dimRow = dimR;
100+
dimCol = dimC;
101+
ax = _ax;
102+
}
103+
int dimRow;
104+
int dimCol;
105+
Dim ax;
106+
};
107+
108+
std::vector<StStep> makePlan(std::vector<std::vector<bool>> sparseMatMap)
109+
{
110+
std::vector<StStep> ans;
111+
std::vector<std::vector<bool>> visitedMap(sparseMatMap.size(), std::vector<bool>(sparseMatMap[0].size(), false));
112+
visitedMap[0][0] = true;
113+
for (int row = 0; row < sparseMatMap.size(); row++)
114+
{
115+
for (int col = 0; col < sparseMatMap[row].size(); col++)
116+
{
117+
if (sparseMatMap[row][col])
118+
{
119+
for (int c = 0; c <= col; c++)
120+
{
121+
if (!visitedMap[0][c])
122+
{
123+
visitedMap[0][c] = true;
124+
ans.emplace_back(0, c - 1, Dim::Col);
125+
}
126+
}
127+
for (int r = 0; r <= row; r++)
128+
{
129+
if (!visitedMap[r][col])
130+
{
131+
visitedMap[r][col] = true;
132+
ans.emplace_back(r - 1, col, Dim::Row);
133+
}
134+
}
135+
}
136+
}
137+
}
138+
return ans;
139+
}
140+
141+
void MakeMinStMat(InputArray src, OutputArray dst, int rowStep, int colStep)
142+
{
143+
CV_Assert(rowStep * colStep == 0); // one of "rowStep" or "colStep" is required to be 0.
144+
145+
Mat src_ = src.getMat();
146+
Mat dst_ = dst.getMat();
147+
uchar* srcPtr1 = src_.ptr<uchar>(0, 0);
148+
uchar* srcPtr2 = src_.ptr<uchar>(rowStep, colStep);
149+
uchar* dstPtr = dst_.ptr<uchar>(0, 0);
150+
for (int row = 0; row < src.rows() - rowStep; row++)
151+
{
152+
for (int col = 0; col < src.cols() - colStep; col++)
153+
{
154+
for (int c = 0; c < src.channels(); c++)
155+
{
156+
*dstPtr = min(*srcPtr1, *srcPtr2);
157+
srcPtr1++;
158+
srcPtr2++;
159+
dstPtr++;
160+
}
161+
}
162+
srcPtr1 += colStep * src.channels();
163+
srcPtr2 += colStep * src.channels();
164+
dstPtr += colStep * src.channels();
165+
}
166+
}
167+
void MakeMaxStMat(InputArray src, OutputArray dst, int rowStep, int colStep)
168+
{
169+
CV_Assert(rowStep * colStep == 0); // one of "rowStep" or "colStep" is required to be 0.
170+
171+
Mat src_ = src.getMat();
172+
Mat dst_ = dst.getMat();
173+
uchar* srcPtr1 = src_.ptr<uchar>(0, 0);
174+
uchar* srcPtr2 = src_.ptr<uchar>(rowStep, colStep);
175+
uchar* dstPtr = dst_.ptr<uchar>(0, 0);
176+
for (int row = 0; row < src.rows(); row++)
177+
{
178+
for (int col = 0; col < src.cols(); col++)
179+
{
180+
*dstPtr = max(*srcPtr1, *srcPtr2);
181+
}
182+
}
183+
}
184+
56185
void dilate(InputArray src, OutputArray dst, InputArray kernel,
57186
Point anchor, int iterations,
58187
int borderType, const Scalar& borderValue)
@@ -66,7 +195,6 @@ void erode(InputArray _src, OutputArray _dst, InputArray _kernel,
66195
//---------------------------
67196
// checking input
68197
uchar ZERO = 255;
69-
// op = ...?
70198

71199
Mat src = _src.getMat();
72200
Mat dst = _dst.getMat();
@@ -94,180 +222,82 @@ void erode(InputArray _src, OutputArray _dst, InputArray _kernel,
94222
Mat expandedSrc(src.rows + kernel.rows, src.cols + kernel.cols, src.type());
95223
cv::copyMakeBorder(src, expandedSrc, anchor.y, kernel.cols - 1 - anchor.y, anchor.x, kernel.rows - 1 - anchor.x, borderType, bV);
96224

225+
// generating a set of rectangles that covers whole kernel
226+
std::vector<Rect> rects = GetCoveringRectangles(kernel);
227+
97228
// log2 table construction
98229
int len = max(kernel.rows, kernel.cols) + 1;
99-
int* lg = new int[len];
100-
lg[1] = 0;
230+
std::vector<int> lg(len);
101231
for (int i = 2; i < len; i++) lg[i] = lg[i >> 1] + 1;
102232

103-
// generating a set of rectangles that covers whole kernel
104-
// todo: implement good algorithm
105-
int kCount = 0;
106-
int buffSize = kernel.rows * 2;
107-
Rect* rects = new Rect[buffSize];
108-
if (rects != NULL)
233+
// 矩形を2冪矩形に分解 & 登場した2冪矩形の情報を位置と幅高さの指数で記録
234+
std::vector<std::vector<bool>> sparseMatMap(lg[kernel.rows] + 1, std::vector<bool>(lg[kernel.cols] + 1, false));
235+
std::vector<Rect> powerOf2Rects;
236+
for (int i = 0; i < rects.size(); i++)
109237
{
110-
// bad implementation; just separating by line.
111-
for (int row = 0; row < kernel.rows; row++)
112-
{
113-
uchar pre = 0;
114-
for (int col = 0; col < kernel.cols; col++)
115-
{
116-
if (kernel.ptr(row)[col] == 0)
117-
{
118-
if (pre == 1)
119-
{
120-
rects[kCount].width = col - rects[kCount].x;
121-
kCount++;
122-
}
123-
}
124-
else
125-
{
126-
if (pre == 0)
127-
{
128-
rects[kCount].y = row;
129-
rects[kCount].height = 1;
130-
rects[kCount].x = col;
131-
}
132-
}
133-
pre = kernel.ptr(row)[col];
134-
}
135-
if (pre == 1)
136-
{
137-
rects[kCount].width = kernel.cols - rects[kCount].x;
138-
kCount++;
139-
}
140-
}
141-
}
238+
Rect rect = rects[i];
239+
int lgCols = lg[rect.width];
240+
int lgRows = lg[rect.height];
241+
bool isColDivisionRequired = (1 << lgCols) < rect.width;
242+
bool isRowDivisionRequired = (1 << lgRows) < rect.height;
142243

143-
// calculate required mats in sparsetable
144-
// sparseTable[lnKcol][lnKrow] can be calculated from
145-
// sparseTable[lnKcol - 1][lnKrow] or sparseTable[lnKcol][lnKrow - 1].
146-
//
147-
// todo: implement better algorithm.
148-
Mat stRequiredMatMap(lg[kernel.rows] + 1, lg[kernel.cols] + 1, CV_8UC1);
149-
stRequiredMatMap.setTo(0);
150-
for (int i = 0; i < kCount; i++)
151-
{
152-
stRequiredMatMap.ptr(lg[rects[i].height])[lg[rects[i].width]] = 1;
153-
}
154-
#if 0
155-
cv::resize(stRequiredMatMap, stRequiredMatMap, cv::Size(), 10, 10, 0);
156-
imshow("debug", stRequiredMatMap);
157-
#endif
158-
159-
// temporary implementation; only row separation is supported.
160-
int szColDepth = stRequiredMatMap.cols;
161-
int szRowDepth = 1;
162-
163-
int stSizes[] = { szRowDepth, szColDepth, expandedSrc.rows, expandedSrc.cols };
164-
Mat sparseTable(4, stSizes, src.type(), Scalar(0));
165-
166-
// sparse table construction
167-
uchar* ptr = sparseTable.ptr();
168-
uchar* refPtr = expandedSrc.ptr();
244+
sparseMatMap[lgRows][lgCols] = true;
169245

170-
for (int row = 0; row < expandedSrc.rows; row++)
171-
{
172-
for (int col = 0; col < expandedSrc.cols; col++)
173-
{
174-
for (unsigned int c = 0; c < src.channels(); c++)
175-
{
176-
*ptr = *refPtr;
177-
ptr++;
178-
refPtr++;
179-
}
180-
}
246+
powerOf2Rects.emplace_back(rect.x, rect.y, lgCols, lgRows);
247+
if (isColDivisionRequired)
248+
powerOf2Rects.emplace_back(rect.x + rect.width - (1 << lgCols), rect.y, lgCols, lgRows);
249+
if (isRowDivisionRequired)
250+
powerOf2Rects.emplace_back(rect.x + rect.width, rect.y - (1 << lgRows), lgCols, lgRows);
251+
if (isColDivisionRequired && isRowDivisionRequired)
252+
powerOf2Rects.emplace_back(rect.x + rect.width - (1 << lgCols), rect.y - (1 << lgRows), lgCols, lgRows);
181253
}
182-
for (int lgColCnt = 1; lgColCnt < szColDepth; lgColCnt++)
183-
{
184-
int b = (1 << lgColCnt) - 1;
185-
int colROfs = sparseTable.step.p[3] * (1 << (lgColCnt - 1));
186-
int colSkipOfs = b * sparseTable.step.p[3];
187254

188-
for (int row = 0; row < expandedSrc.rows; row++)
189-
{
190-
for (int col = 0; col < expandedSrc.cols - b; col++)
191-
{
192-
for (unsigned int c = 0; c < src.channels(); c++)
193-
{
194-
uchar* l = ptr - sparseTable.step.p[1];
195-
uchar* r = l + colROfs;
196-
*ptr = min(*l, *r);
197-
ptr++;
198-
}
199-
}
200-
ptr += colSkipOfs;
201-
}
202-
}
203-
for (int lgRowCnt = 1; lgRowCnt < szRowDepth; lgRowCnt++)
255+
// スパーステーブルの生成計画を立てる; planning how to calculate required mats in sparsetable
256+
std::vector<StStep> stProcess = makePlan(sparseMatMap);
257+
258+
// スパーステーブルの生成
259+
std::vector<std::vector<Mat*>> st = std::vector<std::vector<Mat*>>(lg[kernel.rows] + 1, std::vector<Mat*>(lg[kernel.cols] + 1));
260+
st[0][0] = &expandedSrc;
261+
for (int i = 0; i < stProcess.size(); i++)
204262
{
205-
int a = (1 << lgRowCnt) - 1;
206-
int rowROfs = sparseTable.step.p[2] * (1 << (lgRowCnt - 1));
207-
for (int lgColCnt = 0; lgColCnt < szColDepth; lgColCnt++)
263+
StStep step = stProcess[i];
264+
switch (step.ax)
208265
{
209-
int b = (1 << lgColCnt) - 1;
210-
int colROfs = sparseTable.step.p[3] * (1 << (lgColCnt - 1));
211-
int colSkipOfs = b * sparseTable.step.p[3];
212-
213-
for (int row = 0; row < expandedSrc.rows - a; row++)
214-
{
215-
for (int col = 0; col < expandedSrc.cols - b; col++)
216-
{
217-
for (unsigned int c = 0; c < src.channels(); c++)
218-
{
219-
uchar* l = ptr - sparseTable.step.p[0];
220-
uchar* r = l + rowROfs;
221-
*ptr = min(*l, *r);
222-
ptr++;
223-
}
224-
}
225-
ptr += colSkipOfs;
226-
}
227-
ptr += a * sparseTable.step.p[2];
266+
case Dim::Col:
267+
st[step.dimRow][step.dimCol + 1] = new Mat(expandedSrc.rows, expandedSrc.cols, expandedSrc.type());
268+
MakeMinStMat(*st[step.dimRow][step.dimCol], *st[step.dimRow][step.dimCol + 1], 0, 1 << step.dimCol);
269+
break;
270+
case Dim::Row:
271+
st[step.dimRow + 1][step.dimCol] = new Mat(expandedSrc.rows, expandedSrc.cols, expandedSrc.type());
272+
MakeMinStMat(*st[step.dimRow][step.dimCol], *st[step.dimRow + 1][step.dimCol], 1 << step.dimRow, 0);
273+
break;
228274
}
229275
}
230276

231-
// result construction
232-
for (int i = 0; i < kCount; i++)
277+
// 結果構築
278+
int aaa; //???
279+
for (int i = 0; i < powerOf2Rects.size(); i++)
233280
{
234-
int lgRectRows = lg[rects[i].height];
235-
int lgRectCols = lg[rects[i].width];
236-
int ofsTB = (rects[i].height - (1 << lgRectRows)) * sparseTable.step.p[2];
237-
int ofsLR = (rects[i].width - (1 << lgRectCols)) * sparseTable.step.p[3];
238-
int sideBorderSkipStep = (kernel.cols - 1) * sparseTable.step.p[3];
239-
uchar* vLT = sparseTable.ptr()
240-
+ sparseTable.step.p[0] * lgRectRows
241-
+ sparseTable.step.p[1] * lgRectCols
242-
+ rects[i].y * sparseTable.step.p[2]
243-
+ rects[i].x * sparseTable.step.p[3];
244-
uchar* vLB = vLT + ofsTB;
245-
uchar* vRT = vLT + ofsLR;
246-
uchar* vRB = vRT + ofsTB;
281+
Rect rect = powerOf2Rects[i];
282+
Mat* sparseMat = st[rect.height][rect.width];
283+
uchar* srcPtr = sparseMat->ptr() + sparseMat->step.p[0] * rect.y + sparseMat->step.p[1] * rect.x;
247284
uchar* dstPtr = dst.ptr();
285+
int sideBorderSkipStep = (kernel.cols - 1) * sparseMat->step.p[1];
248286

249287
for (int row = 0; row < src.rows; row++)
250288
{
251289
for (int col = 0; col < src.cols; col++)
252290
{
253291
for (int c = 0; c < src.channels(); c++)
254292
{
255-
*dstPtr = min(*dstPtr, min(min(*vLT, *vLB), min(*vRT, *vRB)));
256-
vLT++;
257-
vLB++;
258-
vRT++;
259-
vRB++;
293+
*dstPtr = min(*dstPtr, *srcPtr);
294+
srcPtr++;
260295
dstPtr++;
261296
}
262297
}
263-
vLT += sideBorderSkipStep;
264-
vLB += sideBorderSkipStep;
265-
vRT += sideBorderSkipStep;
266-
vRB += sideBorderSkipStep;
298+
srcPtr += sideBorderSkipStep;
267299
}
268300
}
269-
delete[] lg;
270-
delete[] rects;
271301
}
272302

273303
void morphologyEx(InputArray _src, OutputArray _dst, int op,

0 commit comments

Comments
 (0)