Skip to content

Commit fe9150d

Browse files
committed
p2RCovering の省メモリ化
1 parent 83d6db0 commit fe9150d

File tree

2 files changed

+69
-97
lines changed

2 files changed

+69
-97
lines changed

modules/ximgproc/src/sparse_table_morphology.cpp

Lines changed: 58 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -10,112 +10,76 @@
1010
namespace cv {
1111
namespace stMorph {
1212

13-
// Generate list of rectangles whose width and height are power of 2.
14-
// (The width and height values of returned rects ​​are the log2 of the actual values.)
15-
std::vector<Rect> genPow2RectsToCoverKernel(InputArray _kernel)
13+
int log2(int n)
1614
{
17-
CV_Assert(_kernel.type() == CV_8UC1);
18-
19-
Mat kernel = _kernel.getMat();
20-
21-
// generate log2 table
22-
int len = std::max(kernel.rows, kernel.cols) + 1;
23-
std::vector<int> log2(len);
24-
for (int i = 2; i < len; i++) log2[i] = log2[i >> 1] + 1;
25-
26-
// generate sparse table for the kernel
27-
std::vector<std::vector<Mat>> st(log2[kernel.rows] + 1, std::vector<Mat>(log2[kernel.cols] + 1));
28-
st[0][0] = kernel;
29-
int colDepthLim = log2[kernel.cols];
30-
int rowDepthLim = log2[kernel.rows];
31-
for (int colDepth = 1; colDepth <= colDepthLim; colDepth++)
15+
int ans = -1;
16+
while (n > 0)
3217
{
33-
int colStep = 1 << (colDepth - 1);
34-
int colLim = kernel.cols - (1 << colDepth) + 1;
35-
36-
Rect rect1(0, 0, colLim, kernel.rows);
37-
Rect rect2(colStep, 0, colLim, kernel.rows);
38-
Mat src1 = st[0][colDepth - 1](rect1);
39-
Mat src2 = st[0][colDepth - 1](rect2);
40-
st[0][colDepth].create(kernel.size(), kernel.type());
41-
Mat next = st[0][colDepth](rect1);
42-
cv::bitwise_and(src1, src2, next);
43-
if (countNonZero(next) == 0)
44-
{
45-
colDepthLim = colDepth;
46-
break;
47-
}
18+
n /= 2;
19+
ans++;
4820
}
49-
for (int rowDepth = 1; rowDepth <= rowDepthLim; rowDepth++)
50-
{
51-
int nonZero = 0;
21+
return ans;
22+
}
5223

53-
int rowStep = 1 << (rowDepth - 1);
54-
int rowLim = kernel.rows - (1 << rowDepth) + 1;
55-
for (int colDepth = 0; colDepth <= colDepthLim; colDepth++)
56-
{
57-
int colStep = 0;
58-
int colLim = kernel.cols - (1 << colDepth) + 1;
59-
60-
Rect rect1(0, 0, colLim, rowLim);
61-
Rect rect2(colStep, rowStep, colLim, rowLim);
62-
Mat src1 = st[rowDepth - 1][colDepth](rect1);
63-
Mat src2 = st[rowDepth - 1][colDepth](rect2);
64-
st[rowDepth][colDepth].create(kernel.size(), kernel.type());
65-
Mat next = st[rowDepth][colDepth](rect1);
66-
cv::bitwise_and(src1, src2, next);
67-
68-
if (colDepth == 0)
69-
{
70-
nonZero = countNonZero(next);
71-
}
72-
}
73-
if (nonZero == 0)
24+
void findSeeds(const Mat& stNode, std::vector<Rect>& const p2Rects, int rowDepth, int colDepth)
25+
{
26+
int rowOfst = 1 << rowDepth;
27+
int colOfst = 1 << colDepth;
28+
for (int row = 0; row < stNode.rows; row++)
29+
{
30+
for (int col = 0; col < stNode.cols; col++)
7431
{
75-
rowDepthLim = rowDepth;
76-
break;
32+
// select white cells
33+
if (stNode.at<uchar>(row, col) == 0) continue;
34+
35+
// select corner cells
36+
if (col > 0 && stNode.at<uchar>(row, col - 1) == 1
37+
&& col + 1 < stNode.cols && stNode.at<uchar>(row, col + 1) == 1) continue;
38+
if (row > 0 && stNode.at<uchar>(row - 1, col) == 1
39+
&& row + 1 < stNode.rows && stNode.at<uchar>(row + 1, col) == 1) continue;
40+
41+
// zignore if neighboring block is white; will be alive in deeper table
42+
if (col + colOfst < stNode.cols && stNode.at<uchar>(row, col + colOfst) == 1) continue;
43+
if (col - colOfst >= 0 && stNode.at<uchar>(row, col - colOfst) == 1) continue;
44+
if (row + rowOfst < stNode.rows && stNode.at<uchar>(row + rowOfst, col) == 1) continue;
45+
if (row - rowOfst >= 0 && stNode.at<uchar>(row - rowOfst, col) == 1) continue;
46+
47+
p2Rects.emplace_back(col, row, colDepth, rowDepth);
7748
}
7849
}
50+
}
51+
52+
// Generate list of rectangles whose width and height are power of 2.
53+
// (The width and height values of returned rects ​​are the log2 of the actual values.)
54+
std::vector<Rect> genPow2RectsToCoverKernel(InputArray _kernel)
55+
{
56+
CV_Assert(_kernel.type() == CV_8UC1);
57+
58+
Mat kernel = _kernel.getMat();
7959

80-
// find pow2 rectangles
8160
std::vector<Rect> p2Rects;
82-
for (int rowDepth = 0; rowDepth <= rowDepthLim; rowDepth++)
61+
Mat stCache = kernel;
62+
int rowLim = log2(kernel.rows);
63+
int colLim = log2(kernel.cols);
64+
for (int rowDepth = 0; rowDepth <= rowLim; rowDepth++)
8365
{
84-
int rowOfst = 1 << rowDepth;
85-
int rowSkip = rowOfst - 1;
86-
int rowLim = kernel.rows - rowSkip;
87-
int x = rowOfst * kernel.cols;
88-
for (int colDepth = 0; colDepth <= colDepthLim; colDepth++)
66+
Mat st = stCache.clone();
67+
for (int colDepth = 0; colDepth <= colLim; colDepth++)
8968
{
90-
int colOfst = 1 << colDepth;
91-
int colSkip = colOfst - 1;
92-
int colLim = kernel.cols - colSkip;
93-
94-
uchar* ptr = st[rowDepth][colDepth].ptr();
95-
for (int row = 0; row < rowLim; row++)
96-
{
97-
for (int col = 0; col < colLim; col++, ptr++)
98-
{
99-
// ignore black cell
100-
if (ptr[0] == 0) continue;
101-
102-
// ignore if both sides are white by each axis
103-
if (col > 0 && ptr[-1] == 1
104-
&& col < colLim && ptr[1] == 1) continue;
105-
if (row > 0 && ptr[-kernel.cols]
106-
&& row < rowLim && ptr[kernel.cols] == 1) continue;
107-
108-
// ignore if neighboring block is white; will be alive in deeper table
109-
if (col + colOfst < colLim && ptr[colOfst] == 1) continue;
110-
if (col - colOfst >= 0 && ptr[-colOfst] == 1) continue;
111-
if (row + rowOfst < rowLim && ptr[x] == 1) continue;
112-
if (row - rowOfst >= 0 && ptr[-x] == 1) continue;
113-
114-
p2Rects.emplace_back(col, row, colDepth, rowDepth);
115-
}
116-
ptr += colSkip;
117-
}
69+
findSeeds(st, p2Rects, rowDepth, colDepth);
70+
int colStep = 1 << colDepth;
71+
if (st.cols - colStep < 0) break;
72+
Rect s1(0, 0, st.cols - colStep, st.rows);
73+
Rect s2(colStep, 0, st.cols - colStep, st.rows);
74+
cv::min(st(s1), st(s2), st);
75+
if (countNonZero(st) == 0) break;
11876
}
77+
int rowStep = 1 << rowDepth;
78+
if (stCache.rows - rowStep < 0) break;
79+
Rect s1(0, 0, stCache.cols, stCache.rows - rowStep);
80+
Rect s2(0, rowStep, stCache.cols, stCache.rows - rowStep);
81+
cv::min(stCache(s1), stCache(s2), stCache);
82+
if (countNonZero(stCache) == 0) break;
11983
}
12084
return p2Rects;
12185
}

modules/ximgproc/test/test_sparse_table_morphology.cpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,12 @@ Mat knBig() { return getStructuringElement(cv::MorphShapes::MORPH_RECT, Size(201
4545
Mat knAsymm (){
4646
return (Mat_<uchar>(5, 5) << 0,0,0,0,0, 0,0,1,0,0, 0,1,0,0,0, 0,0,0,0,0, 0,0,1,0,0);
4747
}
48-
Mat knRnd(int size)
48+
Mat knRnd(int size, int density)
4949
{
5050
Mat rndMat(size, size, CV_8UC1);
51-
randu(rndMat, 0, 2);
51+
theRNG().state = getTickCount();
52+
randu(rndMat, 0, density + 1);
53+
cv::min(rndMat, 1, rndMat);
5254
return rndMat;
5355
}
5456

@@ -211,7 +213,13 @@ void p2RCov(InputArray kernel)
211213
}
212214
assertArraysIdentical(expected, actual);
213215
}
214-
TEST(ximgproc_StMorph_private, feature_P2RCov_rnd) { p2RCov(knRnd(100)); }
216+
TEST(ximgproc_StMorph_private, feature_P2RCov_rnd1) { p2RCov(knRnd(1000, 1)); }
217+
TEST(ximgproc_StMorph_private, feature_P2RCov_rnd2) { p2RCov(knRnd(1000, 1)); }
218+
TEST(ximgproc_StMorph_private, feature_P2RCov_rnd3) { p2RCov(knRnd(1000, 2)); }
219+
TEST(ximgproc_StMorph_private, feature_P2RCov_rnd4) { p2RCov(knRnd(1000, 2)); }
220+
TEST(ximgproc_StMorph_private, feature_P2RCov_rnd5) { p2RCov(knRnd(1000, 3)); }
221+
TEST(ximgproc_StMorph_private, feature_P2RCov_rnd6) { p2RCov(knRnd(1000, 3)); }
222+
TEST(ximgproc_StMorph_private, feature_P2RCov_kn5) { p2RCov(kn5()); }
215223

216224
#pragma endregion
217225

0 commit comments

Comments
 (0)