Skip to content

Commit db3d66e

Browse files
committed
カーネルから2べき長方形のセットを作る処理を実装
1 parent 048f0db commit db3d66e

File tree

2 files changed

+262
-56
lines changed

2 files changed

+262
-56
lines changed

modules/ximgproc/src/sparse_table_morphology.cpp

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

4343
namespace cv {
4444
namespace ximgproc {
@@ -78,74 +78,120 @@ struct StStep
7878
* - The width and the height of each rectangles are power of 2.
7979
* - Overlappings of rectangles are allowed.
8080
*/
81-
static std::vector<Rect> genPow2RectsToCoverKernel(InputArray _kernel)
81+
std::vector<Rect> genPow2RectsToCoverKernel(InputArray _kernel)
8282
{
83-
std::vector<Rect> rects;
83+
CV_Assert(_kernel.type() == CV_8UC1);
84+
8485
Mat kernel = _kernel.getMat();
85-
int kCount = 0;
8686

87-
// log2 table construction
87+
// generate log2 table
8888
int len = max(kernel.rows, kernel.cols) + 1;
8989
std::vector<int> log2(len);
9090
for (int i = 2; i < len; i++) log2[i] = log2[i >> 1] + 1;
9191

92-
// Development note.
93-
// the strategy atm is to separate the kernel with arbitaly rectangles and then place po2Rects on each corners.
94-
//
95-
// Find a set of rectangles which coveres the kernel.
96-
//
97-
// The exact problem is defined and a not-optimal solution is proposed.
98-
// https://stackoverflow.com/questions/22769490/finding-the-smallest-set-of-rectangles-that-covers-the-given-rectilinear-simple
99-
//
100-
// Similer problem and a link to a paper.
101-
// https://stackoverflow.com/questions/31150398/maximal-rectangle-set-cover
102-
//
103-
// The paper. Names the problem "MISR".
104-
// https://home.ttic.edu/~cjulia/papers/rectangles-SODA.pdf ... x-approximation?
105-
// https://home.ttic.edu/~cjulia/papers/MISR.pdf ... (1-e)-approximation?
106-
//
107-
108-
for (int row = 0; row < kernel.rows; row++)
92+
// generate sparse table for the kernel
93+
std::vector<std::vector<Mat>> st(log2[kernel.rows] + 1, std::vector<Mat>(log2[kernel.cols] + 1));
94+
st[0][0] = kernel;
95+
for (int colDepth = 1; colDepth <= log2[kernel.cols]; colDepth++)
10996
{
110-
uchar pre = 0;
111-
for (int col = 0; col < kernel.cols; col++)
97+
int rowStep = 0;
98+
int rowSkip = 0;
99+
int rowLim = kernel.rows - rowSkip;
100+
101+
int colStep = 1 << (colDepth - 1);
102+
int colSkip = (1 << colDepth) - 1;
103+
int colLim = kernel.cols - colSkip;
104+
105+
st[0][colDepth] = Mat::zeros(kernel.rows, kernel.cols, kernel.type());
106+
uchar* ptr1 = st[0][colDepth - 1].ptr();
107+
uchar* ptr2 = st[0][colDepth - 1].ptr(rowStep, colStep);
108+
uchar* dst = st[0][colDepth].ptr();
109+
for (int row = 0; row < rowLim; row++)
112110
{
113-
if (pre == 1 && kernel.ptr(row)[col] == 0)
111+
for (int col = 0; col < colLim; col++)
114112
{
115-
rects[kCount].width = col - rects[kCount].x;
116-
kCount++;
113+
*dst++ = *ptr1++ & *ptr2++;
117114
}
118-
if (pre == 0 && kernel.ptr(row)[col] == 1)
119-
{
120-
rects.emplace_back(col, row, 0, 1);
121-
}
122-
pre = kernel.ptr(row)[col];
115+
ptr1 += colSkip;
116+
ptr2 += colSkip;
117+
dst += colSkip;
123118
}
124-
if (pre == 1)
119+
}
120+
for (int rowDepth = 1; rowDepth <= log2[kernel.rows]; rowDepth++)
121+
{
122+
int rowStep = 1 << (rowDepth - 1);
123+
int rowSkip = (1 << rowDepth) - 1;
124+
int rowLim = kernel.rows - rowSkip;
125+
for (int colDepth = 0; colDepth <= log2[kernel.cols]; colDepth++)
125126
{
126-
rects[kCount].width = kernel.cols - rects[kCount].x;
127-
kCount++;
127+
int colStep = 0;
128+
int colSkip = (1 << colDepth) - 1;
129+
int colLim = kernel.cols - colSkip;
130+
131+
st[rowDepth][colDepth] = Mat::zeros(kernel.rows, kernel.cols, kernel.type());
132+
uchar* ptr1 = st[rowDepth - 1][colDepth].ptr();
133+
uchar* ptr2 = st[rowDepth - 1][colDepth].ptr(rowStep, colStep);
134+
uchar* dst = st[rowDepth][colDepth].ptr();
135+
for (int row = 0; row < rowLim; row++)
136+
{
137+
for (int col = 0; col < colLim; col++)
138+
{
139+
*dst++ = *ptr1++ & *ptr2++;
140+
}
141+
ptr1 += colSkip;
142+
ptr2 += colSkip;
143+
dst += colSkip;
144+
}
128145
}
129146
}
130147

131-
std::vector<Rect> pow2Rects;
132-
for (int i = 0; i < rects.size(); i++)
148+
// find pow2 rectangles
149+
std::vector<Rect> p2Rects;
150+
for (int rowDepth = 0; rowDepth <= log2[kernel.rows]; rowDepth++)
133151
{
134-
Rect rect = rects[i];
135-
int lgCols = log2[rect.width];
136-
int lgRows = log2[rect.height];
137-
bool isColDivisionRequired = (1 << lgCols) < rect.width;
138-
bool isRowDivisionRequired = (1 << lgRows) < rect.height;
139-
140-
pow2Rects.emplace_back(rect.x, rect.y, lgCols, lgRows);
141-
if (isColDivisionRequired)
142-
pow2Rects.emplace_back(rect.x + rect.width - (1 << lgCols), rect.y, lgCols, lgRows);
143-
if (isRowDivisionRequired)
144-
pow2Rects.emplace_back(rect.x + rect.width, rect.y - (1 << lgRows), lgCols, lgRows);
145-
if (isColDivisionRequired && isRowDivisionRequired)
146-
pow2Rects.emplace_back(rect.x + rect.width - (1 << lgCols), rect.y - (1 << lgRows), lgCols, lgRows);
152+
int rowSkip = (1 << rowDepth) - 1;
153+
int rowLim = kernel.rows - rowSkip;
154+
for (int colDepth = 0; colDepth <= log2[kernel.cols]; colDepth++)
155+
{
156+
int colSkip = (1 << colDepth) - 1;
157+
int colLim = kernel.cols - colSkip;
158+
159+
uchar* ptr = st[rowDepth][colDepth].ptr();
160+
for (int row = 0; row < rowLim; row++)
161+
{
162+
for (int col = 0; col < colLim; col++, ptr++)
163+
{
164+
if (ptr[0] == 0) continue;
165+
166+
if (0 < row && ptr[-1] == 1
167+
&& row < rowLim - 1 && ptr[1] == 1
168+
&& 0 < col && ptr[-1] == 1
169+
&& col < colLim - 1 && ptr[1] == 1) continue;
170+
171+
if (rowDepth < log2[kernel.rows] &&
172+
(st[rowDepth + 1][colDepth].ptr(row, col)[0] == 1 ||
173+
(row > (1 << rowDepth) - 1 &&
174+
st[rowDepth + 1][colDepth].ptr(row - (1 << (rowDepth)), col)[0] == 1
175+
)
176+
)
177+
) continue;
178+
179+
if (colDepth < log2[kernel.cols] &&
180+
(st[rowDepth][colDepth + 1].ptr(row, col)[0] == 1 ||
181+
(col > (1 << colDepth) - 1 &&
182+
st[rowDepth][colDepth + 1].ptr(row, col - (1 << (colDepth)))[0] == 1
183+
)
184+
)
185+
) continue;
186+
187+
p2Rects.emplace_back(col, row, colDepth, rowDepth);
188+
}
189+
ptr += colSkip;
190+
}
191+
}
147192
}
148-
return pow2Rects;
193+
194+
return p2Rects;
149195
}
150196

151197
/*
@@ -316,7 +362,7 @@ void erode(InputArray _src, OutputArray _dst, InputArray _kernel,
316362
std::vector<StStep> stProcess = makePlan(sparseMatMap);
317363

318364
// スパーステーブルの生成; generate sparse table
319-
std::vector<std::vector<Mat*>> st = std::vector<std::vector<Mat*>>(log2[kernel.rows] + 1, std::vector<Mat*>(log2[kernel.cols] + 1));
365+
std::vector<std::vector<Mat*>> st(log2[kernel.rows] + 1, std::vector<Mat*>(log2[kernel.cols] + 1));
320366
st[0][0] = &expandedSrc;
321367
for (int i = 0; i < stProcess.size(); i++)
322368
{

modules/ximgproc/test/test_sparse_table_morphology.cpp

Lines changed: 163 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ namespace st_morphology {
1111
TEST(ximgproc_SparseTableMorph, compare_with_original_erode)
1212
{
1313
// preparation
14-
int kRadius = 100;
15-
Size sz(200, 150);
16-
// Size sz = szVGA;
14+
int kRadius = 10;
15+
//Size sz(200, 150);
16+
Size sz = szVGA;
1717
int type = CV_8UC3;
1818

1919
int kSize = kRadius * 2 + 1;
@@ -68,5 +68,165 @@ TEST(ximgproc_SparseTableMorph, compare_with_original_erode)
6868
CV_Assert(max == 0);
6969
}
7070

71+
72+
std::tuple<std::vector<std::vector<Mat>>, std::vector<Rect>> genPow2RectsToCoverKernel_dev(InputArray _kernel)
73+
{
74+
CV_Assert(_kernel.type() == CV_8UC1);
75+
76+
Mat kernel = _kernel.getMat();
77+
78+
// generate log2 table
79+
int len = max(kernel.rows, kernel.cols) + 1;
80+
std::vector<int> log2(len);
81+
for (int i = 2; i < len; i++) log2[i] = log2[i >> 1] + 1;
82+
83+
// generate sparse table for the kernel
84+
std::vector<std::vector<Mat>> st(log2[kernel.rows] + 1, std::vector<Mat>(log2[kernel.cols] + 1));
85+
st[0][0] = kernel;
86+
for (int colDepth = 1; colDepth <= log2[kernel.cols]; colDepth++)
87+
{
88+
int rowStep = 0;
89+
int rowSkip = 0;
90+
int rowLim = kernel.rows - rowSkip;
91+
92+
int colStep = 1 << (colDepth - 1);
93+
int colSkip = (1 << colDepth) - 1;
94+
int colLim = kernel.cols - colSkip;
95+
96+
st[0][colDepth] = Mat::zeros(kernel.rows, kernel.cols, kernel.type());
97+
uchar* ptr1 = st[0][colDepth - 1].ptr();
98+
uchar* ptr2 = st[0][colDepth - 1].ptr(rowStep, colStep);
99+
uchar* dst = st[0][colDepth].ptr();
100+
for (int row = 0; row < rowLim; row++)
101+
{
102+
for (int col = 0; col < colLim; col++)
103+
{
104+
*dst++ = *ptr1++ & *ptr2++;
105+
}
106+
ptr1 += colSkip;
107+
ptr2 += colSkip;
108+
dst += colSkip;
109+
}
110+
}
111+
for (int rowDepth = 1; rowDepth <= log2[kernel.rows]; rowDepth++)
112+
{
113+
int rowStep = 1 << (rowDepth - 1);
114+
int rowSkip = (1 << rowDepth) - 1;
115+
int rowLim = kernel.rows - rowSkip;
116+
for (int colDepth = 0; colDepth <= log2[kernel.cols]; colDepth++)
117+
{
118+
int colStep = 0;
119+
int colSkip = (1 << colDepth) - 1;
120+
int colLim = kernel.cols - colSkip;
121+
122+
st[rowDepth][colDepth] = Mat::zeros(kernel.rows, kernel.cols, kernel.type());
123+
uchar* ptr1 = st[rowDepth - 1][colDepth].ptr();
124+
uchar* ptr2 = st[rowDepth - 1][colDepth].ptr(rowStep, colStep);
125+
uchar* dst = st[rowDepth][colDepth].ptr();
126+
for (int row = 0; row < rowLim; row++)
127+
{
128+
for (int col = 0; col < colLim; col++)
129+
{
130+
*dst++ = *ptr1++ & *ptr2++;
131+
}
132+
ptr1 += colSkip;
133+
ptr2 += colSkip;
134+
dst += colSkip;
135+
}
136+
}
137+
}
138+
139+
// find pow2 rectangles
140+
std::vector<Rect> p2Rects;
141+
for (int rowDepth = 0; rowDepth <= log2[kernel.rows]; rowDepth++)
142+
{
143+
int rowSkip = (1 << rowDepth) - 1;
144+
int rowLim = kernel.rows - rowSkip;
145+
for (int colDepth = 0; colDepth <= log2[kernel.cols]; colDepth++)
146+
{
147+
int colSkip = (1 << colDepth) - 1;
148+
int colLim = kernel.cols - colSkip;
149+
150+
uchar* ptr = st[rowDepth][colDepth].ptr();
151+
for (int row = 0; row < rowLim; row++)
152+
{
153+
for (int col = 0; col < colLim; col++, ptr++)
154+
{
155+
if (ptr[0] == 0) continue;
156+
157+
if (0 < row && ptr[-1] == 1
158+
&& row < rowLim - 1 && ptr[1] == 1
159+
&& 0 < col && ptr[-1] == 1
160+
&& col < colLim - 1 && ptr[1] == 1) continue;
161+
162+
if (rowDepth < log2[kernel.rows] &&
163+
(st[rowDepth + 1][colDepth].ptr(row, col)[0] == 1 ||
164+
(row > (1 << rowDepth) - 1 &&
165+
st[rowDepth + 1][colDepth].ptr(row - (1 << (rowDepth)), col)[0] == 1
166+
)
167+
)
168+
) continue;
169+
170+
if (colDepth < log2[kernel.cols] &&
171+
(st[rowDepth][colDepth + 1].ptr(row, col)[0] == 1 ||
172+
(col > (1 << colDepth) - 1 &&
173+
st[rowDepth][colDepth + 1].ptr(row, col - (1 << (colDepth)))[0] == 1
174+
)
175+
)
176+
) continue;
177+
178+
p2Rects.emplace_back(col, row, colDepth, rowDepth);
179+
}
180+
ptr += colSkip;
181+
}
182+
}
183+
}
184+
185+
return { st, p2Rects };
186+
}
187+
TEST(develop, POW2RECT_COVERING)
188+
{
189+
int kSize = 11;
190+
Size kernelSize(kSize, kSize);
191+
Mat kernel = getStructuringElement(MorphShapes::MORPH_ELLIPSE, kernelSize);
192+
193+
std::tuple<std::vector<std::vector<Mat>>, std::vector<Rect>> ret = genPow2RectsToCoverKernel_dev(kernel);
194+
std::vector<std::vector<Mat>> st = std::get<0>(ret);
195+
std::vector<Rect> rects = std::get<1>(ret);
196+
197+
// visualize
198+
Mat concatSt;
199+
std::vector<Mat> hconMat(st.size(), Mat());
200+
for (int row = 0; row < st.size(); row++) hconcat(st[row], hconMat[row]); vconcat(hconMat, concatSt);
201+
resize(concatSt *255, concatSt, Size(), 10, 10, InterpolationFlags::INTER_NEAREST);
202+
imshow("result", concatSt);
203+
204+
int rate = 40;
205+
resize(kernel * 255, kernel, Size(), rate, rate, InterpolationFlags::INTER_NEAREST);
206+
cvtColor(kernel, kernel, cv::COLOR_GRAY2BGR);
207+
Scalar color[20]{
208+
Scalar(83, 89, 73), Scalar(49, 238, 73), Scalar(220, 192, 189), Scalar(174, 207, 34), Scalar(144, 169, 187),
209+
Scalar(137, 94, 76), Scalar(42, 11, 215), Scalar(113, 11, 204), Scalar(71, 124, 8), Scalar(192, 38, 8),
210+
Scalar(82, 201, 8), Scalar(70, 7, 112), Scalar(166, 219, 201), Scalar(154, 173, 0), Scalar(132, 127, 139),
211+
Scalar(154, 1, 68), Scalar(231, 131, 56), Scalar(206, 238, 136), Scalar(188, 78, 173), Scalar(27, 178, 206)
212+
};
213+
for (int i = 0; i < rects.size(); i++)
214+
{
215+
Rect rect = rects[i];
216+
Point lt((rect.x ) * rate + i, (rect.y ) * rate + i);
217+
Point lb((rect.x ) * rate + i, (rect.y + (1 << rect.height)) * rate - 15 + i);
218+
Point rb((rect.x + (1 << rect.width)) * rate - 15 + i, (rect.y + (1 << rect.height)) * rate - 15 + i);
219+
Point rt((rect.x + (1 << rect.width)) * rate - 15 + i, (rect.y ) * rate + i);
220+
cv::line(kernel, lt, lb, color[i], 2);
221+
cv::line(kernel, lb, rb, color[i], 2);
222+
cv::line(kernel, rb, rt, color[i], 2);
223+
cv::line(kernel, rt, lt, color[i], 2);
224+
}
225+
imshow("kernel", kernel);
226+
227+
waitKey();
228+
destroyAllWindows();
229+
}
230+
71231
} //
72232
} // opencv_test

0 commit comments

Comments
 (0)