Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Tetragramm
GitHub Repository: Tetragramm/opencv
Path: blob/master/3rdparty/carotene/src/morph.cpp
16337 views
1
/*
2
* By downloading, copying, installing or using the software you agree to this license.
3
* If you do not agree to this license, do not download, install,
4
* copy or use the software.
5
*
6
*
7
* License Agreement
8
* For Open Source Computer Vision Library
9
* (3-clause BSD License)
10
*
11
* Copyright (C) 2014, NVIDIA Corporation, all rights reserved.
12
* Third party copyrights are property of their respective owners.
13
*
14
* Redistribution and use in source and binary forms, with or without modification,
15
* are permitted provided that the following conditions are met:
16
*
17
* * Redistributions of source code must retain the above copyright notice,
18
* this list of conditions and the following disclaimer.
19
*
20
* * Redistributions in binary form must reproduce the above copyright notice,
21
* this list of conditions and the following disclaimer in the documentation
22
* and/or other materials provided with the distribution.
23
*
24
* * Neither the names of the copyright holders nor the names of the contributors
25
* may be used to endorse or promote products derived from this software
26
* without specific prior written permission.
27
*
28
* This software is provided by the copyright holders and contributors "as is" and
29
* any express or implied warranties, including, but not limited to, the implied
30
* warranties of merchantability and fitness for a particular purpose are disclaimed.
31
* In no event shall copyright holders or contributors be liable for any direct,
32
* indirect, incidental, special, exemplary, or consequential damages
33
* (including, but not limited to, procurement of substitute goods or services;
34
* loss of use, data, or profits; or business interruption) however caused
35
* and on any theory of liability, whether in contract, strict liability,
36
* or tort (including negligence or otherwise) arising in any way out of
37
* the use of this software, even if advised of the possibility of such damage.
38
*/
39
40
#include "common.hpp"
41
42
#include <algorithm>
43
#include <limits>
44
#include <vector>
45
#include <cstring>
46
47
namespace CAROTENE_NS {
48
49
bool isMorph3x3Supported(const Size2D &size, BORDER_MODE border)
50
{
51
return isSupportedConfiguration() && size.width >= 16 &&
52
(border == BORDER_MODE_CONSTANT ||
53
border == BORDER_MODE_REPLICATE);
54
}
55
56
#ifdef CAROTENE_NEON
57
58
namespace {
59
60
struct ErodeVecOp
61
{
62
ErodeVecOp():borderValue(0){}
63
64
ErodeVecOp(BORDER_MODE border, u8 borderValue_) :
65
borderValue(borderValue_)
66
{
67
if (border == BORDER_MODE_REPLICATE)
68
borderValue = std::numeric_limits<u8>::max();
69
}
70
71
inline uint8x16_t operator()(uint8x16_t a, uint8x16_t b) const
72
{
73
return vminq_u8(a, b);
74
}
75
76
inline uint8x8_t operator()(uint8x8_t a, uint8x8_t b) const
77
{
78
return vmin_u8(a, b);
79
}
80
81
inline u8 operator()(u8 a, u8 b) const
82
{
83
return std::min(a, b);
84
}
85
86
u8 borderValue;
87
};
88
89
struct DilateVecOp
90
{
91
DilateVecOp():borderValue(0){}
92
93
DilateVecOp(BORDER_MODE border, u8 borderValue_) :
94
borderValue(borderValue_)
95
{
96
if (border == BORDER_MODE_REPLICATE)
97
borderValue = std::numeric_limits<u8>::min();
98
}
99
100
inline uint8x16_t operator()(uint8x16_t a, uint8x16_t b) const
101
{
102
return vmaxq_u8(a, b);
103
}
104
105
inline uint8x8_t operator()(uint8x8_t a, uint8x8_t b) const
106
{
107
return vmax_u8(a, b);
108
}
109
110
inline u8 operator()(u8 a, u8 b) const
111
{
112
return std::max(a, b);
113
}
114
115
u8 borderValue;
116
};
117
118
template <typename VecOp>
119
void morph3x3(const Size2D &size,
120
const u8 * srcBase, ptrdiff_t srcStride,
121
u8 * dstBase, ptrdiff_t dstStride,
122
BORDER_MODE border, const VecOp & vop)
123
{
124
u8 borderValue = vop.borderValue;
125
ptrdiff_t width = (ptrdiff_t)size.width, height = (ptrdiff_t)size.height;
126
127
const uint8x16_t v_zero = vdupq_n_u8(0);
128
const uint8x16_t v_border = vdupq_n_u8(borderValue);
129
130
uint8x16_t tprev = v_zero, tcurr = v_zero, tnext = v_zero;
131
uint8x16_t t0 = v_zero, t1 = v_zero, t2 = v_zero;
132
133
for (ptrdiff_t y = 0; y < height; ++y)
134
{
135
const u8 * srow0 = y == 0 && border == BORDER_MODE_CONSTANT ? NULL : internal::getRowPtr(srcBase, srcStride, std::max<ptrdiff_t>(y - 1, 0));
136
const u8 * srow1 = internal::getRowPtr(srcBase, srcStride, y);
137
const u8 * srow2 = y + 1 == height && border == BORDER_MODE_CONSTANT ? NULL : internal::getRowPtr(srcBase, srcStride, std::min(y + 1, height - 1));
138
u8 * drow = internal::getRowPtr(dstBase, dstStride, y);
139
140
u8 prevx = 0, currx = 0, nextx = 0;
141
ptrdiff_t x = 0;
142
const ptrdiff_t bwidth = y + 2 < height ? width : (width - 16);
143
144
// perform vertical convolution
145
for ( ; x <= bwidth; x += 16)
146
{
147
internal::prefetch(srow0 + x);
148
internal::prefetch(srow1 + x);
149
internal::prefetch(srow2 + x);
150
151
uint8x16_t x0 = !srow0 ? v_border : vld1q_u8(srow0 + x);
152
uint8x16_t x1 = vld1q_u8(srow1 + x);
153
uint8x16_t x2 = !srow2 ? v_border : vld1q_u8(srow2 + x);
154
155
// calculate values for plain CPU part below if needed
156
if (x + 16 >= bwidth)
157
{
158
ptrdiff_t x3 = x == width ? width - 1 : x;
159
ptrdiff_t x4 = border == BORDER_MODE_CONSTANT ? x3 - 1 : std::max<ptrdiff_t>(x3 - 1, 0);
160
161
if (border == BORDER_MODE_CONSTANT && x4 < 0)
162
prevx = borderValue;
163
else
164
prevx = vop(srow1[x4],
165
vop(srow2 ? srow2[x4] : borderValue,
166
srow0 ? srow0[x4] : borderValue));
167
168
currx = vop(srow2 ? srow2[x3] : borderValue, vop(srow1[x3], srow0 ? srow0[x3] : borderValue));
169
}
170
171
// make shift
172
if (x)
173
{
174
tprev = tcurr;
175
tcurr = tnext;
176
}
177
178
// and calculate next value
179
tnext = vop(vop(x0, x1), x2);
180
181
// make extrapolation for the first elements
182
if (!x)
183
{
184
// make border
185
if (border == BORDER_MODE_CONSTANT)
186
tcurr = v_border;
187
else if (border == BORDER_MODE_REPLICATE)
188
tcurr = vdupq_n_u8(vgetq_lane_u8(tnext, 0));
189
190
continue;
191
}
192
193
// combine 3 "shifted" vectors
194
t0 = vextq_u8(tprev, tcurr, 15);
195
t1 = tcurr;
196
t2 = vextq_u8(tcurr, tnext, 1);
197
198
// and add them
199
t0 = vop(t0, vop(t1, t2));
200
201
vst1q_u8(drow + x - 16, t0);
202
}
203
204
x -= 16;
205
if (x == width)
206
--x;
207
208
for ( ; x < width; ++x)
209
{
210
// make extrapolation for the last elements
211
if (x + 1 >= width)
212
{
213
if (border == BORDER_MODE_CONSTANT)
214
nextx = borderValue;
215
else if (border == BORDER_MODE_REPLICATE)
216
nextx = vop(srow2[x], vop(srow1[x], srow0[x]));
217
}
218
else
219
nextx = vop(vop(srow2 ? srow2[x + 1] : borderValue,
220
srow0 ? srow0[x + 1] : borderValue),
221
srow1[x + 1]);
222
223
drow[x] = vop(prevx, vop(currx, nextx));
224
225
// make shift
226
prevx = currx;
227
currx = nextx;
228
}
229
}
230
}
231
232
} // namespace
233
234
#endif
235
236
void erode3x3(const Size2D &size,
237
const u8 * srcBase, ptrdiff_t srcStride,
238
u8 * dstBase, ptrdiff_t dstStride,
239
BORDER_MODE border, u8 borderValue)
240
{
241
internal::assertSupportedConfiguration(isMorph3x3Supported(size, border));
242
#ifdef CAROTENE_NEON
243
morph3x3(size,
244
srcBase, srcStride,
245
dstBase, dstStride,
246
border, ErodeVecOp(border, borderValue));
247
#else
248
(void)size;
249
(void)srcBase;
250
(void)srcStride;
251
(void)dstBase;
252
(void)dstStride;
253
(void)border;
254
(void)borderValue;
255
#endif
256
}
257
258
void dilate3x3(const Size2D &size,
259
const u8 * srcBase, ptrdiff_t srcStride,
260
u8 * dstBase, ptrdiff_t dstStride,
261
BORDER_MODE border, u8 borderValue)
262
{
263
internal::assertSupportedConfiguration(isMorph3x3Supported(size, border));
264
#ifdef CAROTENE_NEON
265
morph3x3(size,
266
srcBase, srcStride,
267
dstBase, dstStride,
268
border, DilateVecOp(border, borderValue));
269
#else
270
(void)size;
271
(void)srcBase;
272
(void)srcStride;
273
(void)dstBase;
274
(void)dstStride;
275
(void)border;
276
(void)borderValue;
277
#endif
278
}
279
280
#ifdef CAROTENE_NEON
281
namespace {
282
283
template<class VecUpdate>
284
void MorphRow(const u8* src, u8* dst, size_t width, s32 cn, size_t ksize)
285
{
286
size_t i, j, k;
287
size_t width16 = (width & -16) * cn;
288
size_t width8 = (width & -8) * cn;
289
width *= cn;
290
291
if (ksize == 1)
292
{
293
for (i = 0; i < width; i++)
294
dst[i] = src[i];
295
return;
296
}
297
298
ksize = ksize*cn;
299
VecUpdate updateOp;
300
switch(cn)
301
{
302
case 1:
303
for (i = 0; i < width16; i += 16)
304
{
305
const u8* sptr = src + i;
306
uint8x16_t s = vld1q_u8(sptr);
307
internal::prefetch(sptr);
308
309
for( k = 1; k < ksize; ++k)
310
s = updateOp(s, vld1q_u8(sptr + k));
311
312
vst1q_u8(dst + i, s);
313
}
314
315
for (; i < width8; i += 8)
316
{
317
const u8* sptr = src + i;
318
uint8x8_t s = vld1_u8(sptr);
319
internal::prefetch(sptr);
320
321
for( k = 1; k < ksize; ++k)
322
s = updateOp(s, vld1_u8(sptr + k));
323
324
vst1_u8(dst + i, s);
325
}
326
break;
327
default:
328
for (i = 0; i < width16; i += 16)
329
{
330
uint8x16_t s = vld1q_u8(src + i);
331
internal::prefetch(src + i);
332
333
for (k = cn; k < ksize; k += cn)
334
s = updateOp(s, vld1q_u8(src + i + k));
335
336
vst1q_u8(dst + i, s);
337
}
338
339
for (; i < width8; i += 8)
340
{
341
uint8x8_t s = vld1_u8(src + i);
342
internal::prefetch(src + i);
343
344
for (k = cn; k < ksize; k += cn)
345
s = updateOp(s, vld1_u8(src + i + k));
346
347
vst1_u8(dst + i, s);
348
}
349
break;
350
}
351
352
ptrdiff_t i0 = i;
353
for( k = 0; k < (size_t)cn; k++, src++, dst++ )
354
{
355
for( i = i0; i <= width - cn*2; i += cn*2 )
356
{
357
const u8* s = src + i;
358
u8 m = s[cn];
359
for( j = cn*2; j < ksize; j += cn )
360
m = updateOp(m, s[j]);
361
dst[i] = updateOp(m, s[0]);
362
dst[i+cn] = updateOp(m, s[j]);
363
}
364
365
for( ; i < width; i += cn )
366
{
367
const u8* s = src + i;
368
u8 m = s[0];
369
for( j = cn; j < ksize; j += cn )
370
m = updateOp(m, s[j]);
371
dst[i] = m;
372
}
373
}
374
}
375
376
template<class VecUpdate>
377
void MorphColumn(const u8** src, u8* dst, ptrdiff_t dststep, size_t count, size_t width, size_t ksize)
378
{
379
size_t i, k;
380
size_t width32 = width & -32;
381
VecUpdate updateOp;
382
383
uint8x16_t x0,x1,s0,s1;
384
if (ksize == 3)
385
{
386
for (; count > 1; count -= 2, dst += dststep * 2, src += 2)
387
{
388
for (i = 0; i < width32; i += 32)
389
{
390
const u8* sptr = src[1] + i;
391
s0 = vld1q_u8(sptr);
392
s1 = vld1q_u8(sptr + 16);
393
internal::prefetch(sptr);
394
395
sptr = src[2] + i;
396
x0 = vld1q_u8(sptr);
397
x1 = vld1q_u8(sptr + 16);
398
internal::prefetch(sptr);
399
400
s0 = updateOp(s0, x0);
401
s1 = updateOp(s1, x1);
402
403
sptr = src[0] + i;
404
x0 = vld1q_u8(sptr);
405
x1 = vld1q_u8(sptr + 16);
406
internal::prefetch(sptr);
407
408
vst1q_u8(dst+i, updateOp(s0, x0));
409
vst1q_u8(dst+i+16, updateOp(s1, x1));
410
411
sptr = src[3] + i;
412
x0 = vld1q_u8(sptr);
413
x1 = vld1q_u8(sptr + 16);
414
internal::prefetch(sptr);
415
vst1q_u8(dst + dststep + i, updateOp(s0, x0));
416
vst1q_u8(dst + dststep + i + 16, updateOp(s1, x1));
417
418
}
419
for(; i < width; i++ )
420
{
421
u8 s = src[1][i];
422
423
for( k = 2; k < ksize; k++ )
424
s = updateOp(s, src[k][i]);
425
426
dst[i] = updateOp(s, src[0][i]);
427
dst[i+dststep] = updateOp(s, src[k][i]);
428
}
429
}
430
}
431
else if (ksize > 1)
432
for (; count > 1; count -= 2, dst += dststep*2, src += 2)
433
{
434
for (i = 0; i < width32; i += 32)
435
{
436
const u8* sptr = src[1] + i;
437
s0 = vld1q_u8(sptr);
438
s1 = vld1q_u8(sptr + 16);
439
internal::prefetch(sptr);
440
for (k = 2; k < ksize; k++)
441
{
442
sptr = src[k] + i;
443
x0 = vld1q_u8(sptr);
444
x1 = vld1q_u8(sptr + 16);
445
internal::prefetch(sptr);
446
447
s0 = updateOp(s0, x0);
448
s1 = updateOp(s1, x1);
449
}
450
451
sptr = src[0] + i;
452
x0 = vld1q_u8(sptr);
453
x1 = vld1q_u8(sptr + 16);
454
internal::prefetch(sptr);
455
456
vst1q_u8(dst+i, updateOp(s0, x0));
457
vst1q_u8(dst+i+16, updateOp(s1, x1));
458
459
sptr = src[k] + i;
460
x0 = vld1q_u8(sptr);
461
x1 = vld1q_u8(sptr + 16);
462
internal::prefetch(sptr);
463
vst1q_u8(dst + dststep + i, updateOp(s0, x0));
464
vst1q_u8(dst + dststep + i + 16, updateOp(s1, x1));
465
}
466
for(; i < width; i++ )
467
{
468
u8 s = src[1][i];
469
470
for( k = 2; k < ksize; k++ )
471
s = updateOp(s, src[k][i]);
472
473
dst[i] = updateOp(s, src[0][i]);
474
dst[i+dststep] = updateOp(s, src[k][i]);
475
}
476
}
477
478
for (; count > 0; count--, dst += dststep, src++)
479
{
480
for (i = 0; i < width32; i += 32)
481
{
482
const u8* sptr = src[0] + i;
483
s0 = vld1q_u8(sptr);
484
s1 = vld1q_u8(sptr + 16);
485
internal::prefetch(sptr);
486
487
for (k = 1; k < ksize; k++)
488
{
489
sptr = src[k] + i;
490
x0 = vld1q_u8(sptr);
491
x1 = vld1q_u8(sptr + 16);
492
internal::prefetch(sptr);
493
s0 = updateOp(s0, x0);
494
s1 = updateOp(s1, x1);
495
}
496
497
vst1q_u8(dst + i, s0);
498
vst1q_u8(dst + i + 16, s1);
499
}
500
for(; i < width; i++ )
501
{
502
u8 s = src[0][i];
503
for( k = 1; k < ksize; k++ )
504
s = updateOp(s, src[k][i]);
505
dst[i] = s;
506
}
507
}
508
}
509
510
template <class Op>
511
inline void morphology(const Size2D &ssize, u32 cn,
512
const u8 * srcBase, ptrdiff_t srcStride,
513
u8 * dstBase, ptrdiff_t dstStride,
514
const Size2D &ksize,
515
size_t anchorX, size_t anchorY,
516
BORDER_MODE rowBorderType, BORDER_MODE columnBorderType,
517
const u8 * borderValues, Margin borderMargin)
518
{
519
//Temporary buffers common for all iterations
520
std::vector<u8> _srcRow(cn*(ssize.width + ksize.width - 1));
521
u8* srcRow = &_srcRow[0];
522
523
size_t bufRows = std::max<size_t>(ksize.height + 3, std::max<size_t>(anchorY, ksize.height-anchorY-1)*2+1);
524
std::vector<u8*> _rows(bufRows);
525
u8** rows = &_rows[0];
526
527
// adjust swidthcn so that the used part of buffers stays compact in memory
528
ptrdiff_t swidthcn = cn*((ssize.width + 15) & -16);// cn * (aligned ssize.width size)
529
std::vector<u8> _ringBuf(swidthcn*bufRows+16);
530
u8 * ringBuf = internal::alignPtr(&_ringBuf[0], 16);
531
532
size_t borderLength = std::max<size_t>(ksize.width - 1, 1) * cn;
533
std::vector<ptrdiff_t> _borderTab(borderLength);
534
ptrdiff_t * borderTab = &_borderTab[0];
535
536
std::vector<u8> _constBorderValue;
537
std::vector<u8> _constBorderRow;
538
u8 * constBorderValue = NULL;
539
u8 * constBorderRow = NULL;
540
if( rowBorderType == BORDER_MODE_CONSTANT || columnBorderType == BORDER_MODE_CONSTANT )
541
{
542
_constBorderValue.resize(borderLength);
543
constBorderValue = &_constBorderValue[0];
544
size_t i;
545
for(i = 0; i < cn; i++)
546
constBorderValue[i] = borderValues[i];
547
for(; i < borderLength; i++)
548
constBorderValue[i] = constBorderValue[i-cn];
549
550
if( columnBorderType == BORDER_MODE_CONSTANT )
551
{
552
_constBorderRow.resize(cn*(ssize.width + ksize.width - 1 + 16));
553
constBorderRow = internal::alignPtr(&_constBorderRow[0], 16);
554
size_t N = (ssize.width + ksize.width - 1)*cn;
555
for( i = 0; i < N; i += borderLength )
556
{
557
size_t n = std::min( borderLength, N - i );
558
for(size_t j = 0; j < n; j++)
559
srcRow[i+j] = constBorderValue[j];
560
}
561
MorphRow<Op>(srcRow, constBorderRow, ssize.width, cn, ksize.width);
562
}
563
}
564
565
Size2D wholeSize(ssize.width + borderMargin.left + borderMargin.right,
566
ssize.height + borderMargin.top + borderMargin.bottom);
567
568
ptrdiff_t dx1 = std::max<ptrdiff_t>(anchorX - (ptrdiff_t)borderMargin.left, 0);
569
ptrdiff_t dx2 = std::max<ptrdiff_t>((ptrdiff_t)ksize.width - anchorX - 1 - (ptrdiff_t)borderMargin.right, 0);
570
// recompute border tables
571
if( dx1 > 0 || dx2 > 0 )
572
{
573
if( rowBorderType == BORDER_MODE_CONSTANT )
574
{
575
memcpy( srcRow, &constBorderValue[0], dx1*cn );
576
memcpy( srcRow + (ssize.width + ksize.width - 1 - dx2)*cn, &constBorderValue[0], dx2*cn );
577
}
578
else
579
{
580
ptrdiff_t xofs1 = std::min<ptrdiff_t>(borderMargin.left, anchorX) - borderMargin.left;
581
582
ptrdiff_t wholeWidth = wholeSize.width;
583
584
ptrdiff_t i, j;
585
for( i = 0; i < dx1; i++ )
586
{
587
ptrdiff_t p0 = (internal::borderInterpolate(i-dx1, wholeWidth, rowBorderType) + xofs1)*cn;
588
for( j = 0; j < (ptrdiff_t)cn; j++ )
589
borderTab[i*cn + j] = p0 + j;
590
}
591
592
for( i = 0; i < dx2; i++ )
593
{
594
ptrdiff_t p0 = (internal::borderInterpolate(wholeWidth + i, wholeWidth, rowBorderType) + xofs1)*cn;
595
for( j = 0; j < (ptrdiff_t)cn; j++ )
596
borderTab[(i + dx1)*cn + j] = p0 + j;
597
}
598
}
599
}
600
601
ptrdiff_t startY, startY0, endY, rowCount;
602
startY = startY0 = std::max<ptrdiff_t>(borderMargin.top - anchorY, 0);
603
endY = std::min<ptrdiff_t>(borderMargin.top + ssize.height + ksize.height - anchorY - 1, wholeSize.height);
604
605
const u8* src = srcBase + (startY - borderMargin.top)*srcStride;
606
u8* dst = dstBase;
607
608
ptrdiff_t width = ssize.width, kwidth = ksize.width;
609
ptrdiff_t kheight = ksize.height, ay = anchorY;
610
ptrdiff_t width1 = ssize.width + kwidth - 1;
611
ptrdiff_t xofs1 = std::min<ptrdiff_t>(borderMargin.left, anchorX);
612
bool makeBorder = (dx1 > 0 || dx2 > 0) && rowBorderType != BORDER_MODE_CONSTANT;
613
ptrdiff_t dy = 0, i = 0;
614
615
src -= xofs1*cn;
616
ptrdiff_t count = endY - startY;
617
618
rowCount = 0;
619
for(;; dst += dstStride*i, dy += i)
620
{
621
ptrdiff_t dcount = bufRows - ay - startY - rowCount + borderMargin.top;
622
dcount = dcount > 0 ? dcount : bufRows - kheight + 1;
623
dcount = std::min(dcount, count);
624
count -= dcount;
625
for( ; dcount-- > 0; src += srcStride )
626
{
627
ptrdiff_t bi = (startY - startY0 + rowCount) % bufRows;
628
u8* brow = ringBuf + bi*swidthcn;
629
630
if( (size_t)(++rowCount) > bufRows )
631
{
632
--rowCount;
633
++startY;
634
}
635
636
memcpy( srcRow + dx1*cn, src, (width1 - dx2 - dx1)*cn );
637
638
if( makeBorder )
639
{
640
for( i = 0; i < (ptrdiff_t)(dx1*cn); i++ )
641
srcRow[i] = src[borderTab[i]];
642
for( i = 0; i < (ptrdiff_t)(dx2*cn); i++ )
643
srcRow[i + (width1 - dx2)*cn] = src[borderTab[i+dx1*cn]];
644
}
645
646
MorphRow<Op>(srcRow, brow, width, cn, ksize.width);
647
}
648
649
ptrdiff_t max_i = std::min<ptrdiff_t>(bufRows, ssize.height - dy + (kheight - 1));
650
for( i = 0; i < max_i; i++ )
651
{
652
ptrdiff_t srcY = internal::borderInterpolate(dy + i + borderMargin.top - ay,
653
wholeSize.height, columnBorderType);
654
if( srcY < 0 ) // can happen only with constant border type
655
rows[i] = constBorderRow;
656
else
657
{
658
if( srcY >= startY + rowCount )
659
break;
660
ptrdiff_t bi = (srcY - startY0) % bufRows;
661
rows[i] = ringBuf + bi*swidthcn;
662
}
663
}
664
if( i < kheight )
665
break;
666
i -= kheight - 1;
667
MorphColumn<Op>((const u8**)rows, dst, dstStride, i, ssize.width*cn, ksize.height);
668
}
669
}
670
671
} // namespace
672
#endif // CAROTENE_NEON
673
674
void erode(const Size2D &ssize, u32 cn,
675
const u8 * srcBase, ptrdiff_t srcStride,
676
u8 * dstBase, ptrdiff_t dstStride,
677
const Size2D &ksize,
678
size_t anchorX, size_t anchorY,
679
BORDER_MODE rowBorderType, BORDER_MODE columnBorderType,
680
const u8 * borderValues, Margin borderMargin)
681
{
682
internal::assertSupportedConfiguration(ssize.width > 0 && ssize.height > 0 &&
683
anchorX < ksize.width && anchorY < ksize.height);
684
#ifdef CAROTENE_NEON
685
morphology<ErodeVecOp>(ssize, cn, srcBase, srcStride, dstBase, dstStride,
686
ksize, anchorX, anchorY, rowBorderType, columnBorderType,
687
borderValues, borderMargin);
688
#else
689
(void)cn;
690
(void)srcBase;
691
(void)srcStride;
692
(void)dstBase;
693
(void)dstStride;
694
(void)rowBorderType;
695
(void)columnBorderType;
696
(void)borderValues;
697
(void)borderMargin;
698
#endif
699
}
700
701
void dilate(const Size2D &ssize, u32 cn,
702
const u8 * srcBase, ptrdiff_t srcStride,
703
u8 * dstBase, ptrdiff_t dstStride,
704
const Size2D &ksize,
705
size_t anchorX, size_t anchorY,
706
BORDER_MODE rowBorderType, BORDER_MODE columnBorderType,
707
const u8 * borderValues, Margin borderMargin)
708
{
709
internal::assertSupportedConfiguration(ssize.width > 0 && ssize.height > 0 &&
710
anchorX < ksize.width && anchorY < ksize.height);
711
#ifdef CAROTENE_NEON
712
morphology<DilateVecOp>(ssize, cn, srcBase, srcStride, dstBase, dstStride,
713
ksize, anchorX, anchorY, rowBorderType, columnBorderType,
714
borderValues, borderMargin);
715
#else
716
(void)cn;
717
(void)srcBase;
718
(void)srcStride;
719
(void)dstBase;
720
(void)dstStride;
721
(void)rowBorderType;
722
(void)columnBorderType;
723
(void)borderValues;
724
(void)borderMargin;
725
#endif
726
}
727
728
} // namespace CAROTENE_NS
729
730