Skip to content

Commit aee9a47

Browse files
committed
事前計算したカーネル分解情報のアイディアを実装
1 parent 8378220 commit aee9a47

File tree

3 files changed

+211
-102
lines changed

3 files changed

+211
-102
lines changed

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

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ namespace stMorph {
3232
*/
3333
CV_EXPORTS_W void erode( InputArray src, OutputArray dst, InputArray kernel,
3434
Point anchor = Point(-1,-1), int iterations = 1,
35-
int borderType = BORDER_CONSTANT,
35+
BorderTypes borderType = BORDER_CONSTANT,
3636
const Scalar& borderValue = morphologyDefaultBorderValue() );
3737

3838
/**
@@ -53,7 +53,7 @@ CV_EXPORTS_W void erode( InputArray src, OutputArray dst, InputArray kernel,
5353
*/
5454
CV_EXPORTS_W void dilate( InputArray src, OutputArray dst, InputArray kernel,
5555
Point anchor = Point(-1,-1), int iterations = 1,
56-
int borderType = BORDER_CONSTANT,
56+
BorderTypes borderType = BORDER_CONSTANT,
5757
const Scalar& borderValue = morphologyDefaultBorderValue() );
5858

5959
/**
@@ -79,7 +79,32 @@ CV_EXPORTS_W void dilate( InputArray src, OutputArray dst, InputArray kernel,
7979
CV_EXPORTS_W void morphologyEx( InputArray src, OutputArray dst,
8080
int op, InputArray kernel,
8181
Point anchor = Point(-1,-1), int iterations = 1,
82-
int borderType = BORDER_CONSTANT,
82+
BorderTypes borderType = BORDER_CONSTANT,
83+
const Scalar& borderValue = morphologyDefaultBorderValue() );
84+
85+
typedef struct _kernelDecompInfo
86+
{
87+
int rows;
88+
int cols;
89+
std::vector<std::vector<std::vector<Point>>> stRects;
90+
Mat plan;
91+
Point anchor;
92+
int iterations;
93+
} kernelDecompInfo;
94+
95+
CV_EXPORTS_W kernelDecompInfo getKernelDecompInfo(InputArray kernel,
96+
Point anchor = Point(-1, -1), int iterations = 1);
97+
CV_EXPORTS_W void erode( InputArray src, OutputArray dst,
98+
kernelDecompInfo kdi,
99+
BorderTypes borderType = BORDER_CONSTANT,
100+
const Scalar& borderValue = morphologyDefaultBorderValue() );
101+
CV_EXPORTS_W void dilate( InputArray src, OutputArray dst,
102+
kernelDecompInfo kdi,
103+
BorderTypes borderType = BORDER_CONSTANT,
104+
const Scalar& borderValue = morphologyDefaultBorderValue() );
105+
CV_EXPORTS_W void morphologyEx( InputArray src, OutputArray dst,
106+
int op, kernelDecompInfo kdi,
107+
BorderTypes borderType = BORDER_CONSTANT,
83108
const Scalar& borderValue = morphologyDefaultBorderValue() );
84109

85110
//! @}

modules/ximgproc/src/sparse_table_morphology.cpp

Lines changed: 100 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -257,20 +257,11 @@ void morphDfs(int minmax, Mat& st, Mat& dst,
257257
}
258258

259259
template <typename T>
260-
void morphOp(Op minmax, InputArray _src, OutputArray _dst, InputArray kernel,
261-
Point anchor, int iterations,
262-
int borderType, const Scalar& borderVal)
260+
void morphOp(Op minmax, InputArray _src, OutputArray _dst, kernelDecompInfo kdi,
261+
BorderTypes borderType, const Scalar& borderVal)
263262
{
264263
T nil = (minmax == Op::Min) ? std::numeric_limits<T>::max() : std::numeric_limits<T>::min();
265264

266-
Mat _kernel = kernel.getMat();
267-
int rowDepthLim = log2(longestRowRunLength(_kernel)) + 1;
268-
int colDepthLim = log2(longestColRunLength(_kernel)) + 1;
269-
std::vector<std::vector<std::vector<Point>>> pow2Rects
270-
= genPow2RectsToCoverKernel(_kernel, rowDepthLim, colDepthLim);
271-
Mat stPlan
272-
= sparseTableFillPlanning(pow2Rects, rowDepthLim, colDepthLim);
273-
274265
Mat src = _src.getMat();
275266
_dst.create(_src.size(), _src.type());
276267
Mat dst = _dst.getMat();
@@ -283,163 +274,176 @@ void morphOp(Op minmax, InputArray _src, OutputArray _dst, InputArray kernel,
283274
{
284275
Mat expandedSrc;
285276
copyMakeBorder(src, expandedSrc,
286-
anchor.y, _kernel.cols - 1 - anchor.y,
287-
anchor.x, _kernel.rows - 1 - anchor.x,
277+
kdi.anchor.y, kdi.cols - 1 - kdi.anchor.y,
278+
kdi.anchor.x, kdi.rows - 1 - kdi.anchor.x,
288279
borderType, bV);
289280
dst.setTo(nil);
290-
morphDfs(minmax, expandedSrc, dst, pow2Rects, stPlan, 0, 0);
281+
morphDfs(minmax, expandedSrc, dst, kdi.stRects, kdi.plan, 0, 0);
291282
src = dst;
292-
} while (--iterations > 0);
283+
} while (--kdi.iterations > 0);
293284
}
294285

295-
void morphOp(Op minmax, InputArray _src, OutputArray _dst, InputArray _kernel,
296-
Point anchor, int iterations,
297-
int borderType, const Scalar& borderVal)
286+
void morphOp(Op minmax, InputArray _src, OutputArray _dst, kernelDecompInfo kdi,
287+
BorderTypes borderType, const Scalar& borderVal)
298288
{
299-
Mat kernel = _kernel.getMat();
300-
if (iterations == 0 || kernel.rows * kernel.cols == 1)
289+
if (kdi.iterations == 0 || kdi.rows * kdi.cols == 1)
301290
{
302291
_src.copyTo(_dst);
303292
return;
304293
}
305-
// Fix kernel in case of it is empty.
306-
if (kernel.empty())
307-
{
308-
kernel = getStructuringElement(MORPH_RECT, Size(1 + iterations * 2, 1 + iterations * 2));
309-
anchor = Point(iterations, iterations);
310-
iterations = 1;
311-
}
312-
if (countNonZero(kernel) == 0)
313-
{
314-
kernel.at<uchar>(0, 0) = 1;
315-
}
316-
// Fix anchor to the center of the kernel.
317-
anchor = stMorph::normalizeAnchor(anchor, kernel.size());
318294

319295
switch (_src.depth())
320296
{
321297
case CV_8U:
322-
morphOp<uchar>(minmax, _src, _dst, kernel, anchor, iterations, borderType, borderVal);
298+
morphOp<uchar>(minmax, _src, _dst, kdi, borderType, borderVal);
323299
return;
324300
case CV_8S:
325-
morphOp<char>(minmax, _src, _dst, kernel, anchor, iterations, borderType, borderVal);
301+
morphOp<char>(minmax, _src, _dst, kdi, borderType, borderVal);
326302
return;
327303
case CV_16U:
328-
morphOp<ushort>(minmax, _src, _dst, kernel, anchor, iterations, borderType, borderVal);
304+
morphOp<ushort>(minmax, _src, _dst, kdi, borderType, borderVal);
329305
return;
330306
case CV_16S:
331-
morphOp<short>(minmax, _src, _dst, kernel, anchor, iterations, borderType, borderVal);
307+
morphOp<short>(minmax, _src, _dst, kdi, borderType, borderVal);
332308
return;
333309
case CV_32S:
334-
morphOp<int>(minmax, _src, _dst, kernel, anchor, iterations, borderType, borderVal);
310+
morphOp<int>(minmax, _src, _dst, kdi, borderType, borderVal);
335311
return;
336312
case CV_32F:
337-
morphOp<float>(minmax, _src, _dst, kernel, anchor, iterations, borderType, borderVal);
313+
morphOp<float>(minmax, _src, _dst, kdi, borderType, borderVal);
338314
return;
339315
case CV_64F:
340-
morphOp<double>(minmax, _src, _dst, kernel, anchor, iterations, borderType, borderVal);
316+
morphOp<double>(minmax, _src, _dst, kdi, borderType, borderVal);
341317
return;
342318
}
343319
}
344320

345-
void dilate(InputArray src, OutputArray dst, InputArray kernel,
346-
Point anchor, int iterations,
347-
int borderType, const Scalar& borderVal)
321+
kernelDecompInfo getKernelDecompInfo(InputArray kernel, Point anchor, int iterations)
348322
{
349-
morphOp(Op::Max, src, dst, kernel, anchor, iterations, borderType, borderVal);
323+
Mat _kernel = kernel.getMat();
324+
// Fix kernel in case of it is empty.
325+
if (_kernel.empty())
326+
{
327+
_kernel = getStructuringElement(MORPH_RECT, Size(1 + iterations * 2, 1 + iterations * 2));
328+
anchor = Point(iterations, iterations);
329+
iterations = 1;
330+
}
331+
if (countNonZero(_kernel) == 0)
332+
{
333+
_kernel.at<uchar>(0, 0) = 1;
334+
}
335+
// Fix anchor to the center of the kernel.
336+
anchor = stMorph::normalizeAnchor(anchor, _kernel.size());
337+
338+
339+
int rowDepthLim = log2(longestRowRunLength(_kernel)) + 1;
340+
int colDepthLim = log2(longestColRunLength(_kernel)) + 1;
341+
std::vector<std::vector<std::vector<Point>>> pow2Rects
342+
= genPow2RectsToCoverKernel(_kernel, rowDepthLim, colDepthLim);
343+
344+
Mat stPlan
345+
= sparseTableFillPlanning(pow2Rects, rowDepthLim, colDepthLim);
346+
347+
anchor = stMorph::normalizeAnchor(anchor, _kernel.size());
348+
349+
return { _kernel.rows, _kernel.cols, pow2Rects, stPlan, anchor, iterations };
350350
}
351351

352-
void erode(InputArray src, OutputArray dst, InputArray kernel,
353-
Point anchor, int iterations,
354-
int borderType, const Scalar& borderVal)
352+
void erode(InputArray src, OutputArray dst, kernelDecompInfo kdi,
353+
BorderTypes borderType, const Scalar& borderVal)
355354
{
356-
morphOp(Op::Min, src, dst, kernel, anchor, iterations, borderType, borderVal);
355+
morphOp(Op::Min, src, dst, kdi, borderType, borderVal);
357356
}
358357

359-
void morphologyEx(InputArray src, OutputArray dst, int op,
360-
InputArray kernel, Point anchor, int iterations,
361-
int borderType, const Scalar& borderVal)
358+
void dilate(InputArray src, OutputArray dst, kernelDecompInfo kdi,
359+
BorderTypes borderType, const Scalar& borderVal)
360+
{
361+
morphOp(Op::Max, src, dst, kdi, borderType, borderVal);
362+
}
363+
364+
void morphologyEx(InputArray src, OutputArray dst, int op, kernelDecompInfo kdi,
365+
BorderTypes borderType, const Scalar& borderVal)
362366
{
363367
CV_INSTRUMENT_REGION();
364368

365369
CV_Assert(!src.empty());
366370

367-
Mat _kernel = kernel.getMat();
368-
if (_kernel.empty())
369-
{
370-
_kernel = getStructuringElement(MORPH_RECT, Size(3, 3), Point(1, 1));
371-
}
372-
373371
Mat _src = src.getMat(), temp;
374372
dst.create(_src.size(), _src.type());
375373
Mat _dst = dst.getMat();
376374

377375
switch (op)
378376
{
379377
case MORPH_ERODE:
380-
stMorph::erode(src, dst, kernel, anchor, iterations, borderType, borderVal);
378+
erode(src, dst, kdi, borderType, borderVal);
381379
break;
382380
case MORPH_DILATE:
383-
stMorph::dilate(src, dst, kernel, anchor, iterations, borderType, borderVal);
381+
dilate(src, dst, kdi, borderType, borderVal);
384382
break;
385383
case MORPH_OPEN:
386-
stMorph::erode(src, dst, kernel, anchor, iterations, borderType, borderVal);
387-
stMorph::dilate(dst, dst, kernel, anchor, iterations, borderType, borderVal);
384+
stMorph::erode(src, dst, kdi, borderType, borderVal);
385+
stMorph::dilate(dst, dst, kdi, borderType, borderVal);
388386
break;
389387
case MORPH_CLOSE:
390-
stMorph::dilate(src, dst, kernel, anchor, iterations, borderType, borderVal);
391-
stMorph::erode(dst, dst, kernel, anchor, iterations, borderType, borderVal);
388+
stMorph::dilate(src, dst, kdi, borderType, borderVal);
389+
stMorph::erode(dst, dst, kdi, borderType, borderVal);
392390
break;
393391
case MORPH_GRADIENT:
394-
stMorph::erode(_src, temp, _kernel, anchor, iterations, borderType, borderVal);
395-
stMorph::dilate(_src, _dst, _kernel, anchor, iterations, borderType, borderVal);
392+
stMorph::erode(_src, temp, kdi, borderType, borderVal);
393+
stMorph::dilate(_src, _dst, kdi, borderType, borderVal);
396394
_dst -= temp;
397395
break;
398396
case MORPH_TOPHAT:
399397
if (_src.data != _dst.data)
400398
temp = _dst;
401-
stMorph::erode(_src, temp, _kernel, anchor, iterations, borderType, borderVal);
402-
stMorph::dilate(temp, temp, _kernel, anchor, iterations, borderType, borderVal);
399+
stMorph::erode(_src, temp, kdi, borderType, borderVal);
400+
stMorph::dilate(temp, temp, kdi, borderType, borderVal);
403401
_dst = _src - temp;
404402
break;
405403
case MORPH_BLACKHAT:
406404
if (_src.data != _dst.data)
407405
temp = _dst;
408-
stMorph::dilate(_src, temp, _kernel, anchor, iterations, borderType, borderVal);
409-
stMorph::erode(temp, temp, _kernel, anchor, iterations, borderType, borderVal);
406+
stMorph::dilate(_src, temp, kdi, borderType, borderVal);
407+
stMorph::erode(temp, temp, kdi, borderType, borderVal);
410408
_dst = temp - _src;
411409
break;
412410
case MORPH_HITMISS:
413-
CV_Assert(_src.type() == CV_8UC1);
414-
if (countNonZero(_kernel) <= 0)
415-
{
416-
_src.copyTo(_dst);
417-
break;
418-
}
419-
{
420-
Mat k1, k2, e1, e2;
421-
k1 = (_kernel == 1);
422-
k2 = (_kernel == -1);
423-
424-
if (countNonZero(k1) <= 0)
425-
e1 = Mat(_src.size(), _src.type(), Scalar(255));
426-
else
427-
stMorph::erode(_src, e1, k1, anchor, iterations, borderType, borderVal);
428-
429-
if (countNonZero(k2) <= 0)
430-
e2 = Mat(_src.size(), _src.type(), Scalar(255));
431-
else
432-
{
433-
Mat _src_complement;
434-
bitwise_not(_src, _src_complement);
435-
stMorph::erode(_src_complement, e2, k2, anchor, iterations, borderType, borderVal);
436-
}
437-
_dst = e1 & e2;
438-
}
439-
break;
411+
CV_Error(cv::Error::StsBadArg, "stMorph doesn't support HITMISS operation");
440412
default:
441413
CV_Error(cv::Error::StsBadArg, "unknown morphological operation");
442414
}
443415
}
444416

417+
//------------------------------------------
418+
void erode(InputArray src, OutputArray dst, InputArray kernel,
419+
Point anchor, int iterations,
420+
BorderTypes borderType, const Scalar& borderVal)
421+
{
422+
kernelDecompInfo kdi = getKernelDecompInfo(kernel, anchor, iterations);
423+
morphOp(Op::Min, src, dst, kdi, borderType, borderVal);
424+
}
425+
426+
void dilate(InputArray src, OutputArray dst, InputArray kernel,
427+
Point anchor, int iterations,
428+
BorderTypes borderType, const Scalar& borderVal)
429+
{
430+
kernelDecompInfo kdi = getKernelDecompInfo(kernel, anchor, iterations);
431+
morphOp(Op::Max, src, dst, kdi, borderType, borderVal);
432+
}
433+
434+
void morphologyEx(InputArray src, OutputArray dst, int op,
435+
InputArray kernel, Point anchor, int iterations,
436+
BorderTypes borderType, const Scalar& borderVal)
437+
{
438+
439+
Mat _kernel = kernel.getMat();
440+
if (_kernel.empty())
441+
{
442+
_kernel = getStructuringElement(MORPH_RECT, Size(3, 3), Point(1, 1));
443+
}
444+
445+
kernelDecompInfo kdi = getKernelDecompInfo(_kernel, anchor, iterations);
446+
morphologyEx(src, dst, op, kdi, borderType, borderVal);
447+
}
448+
445449
}} // cv::stMorph::

0 commit comments

Comments
 (0)