Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Tetragramm
GitHub Repository: Tetragramm/opencv
Path: blob/master/modules/core/src/channels.cpp
16337 views
1
// This file is part of OpenCV project.
2
// It is subject to the license terms in the LICENSE file found in the top-level directory
3
// of this distribution and at http://opencv.org/license.html
4
5
6
#include "precomp.hpp"
7
#include "opencl_kernels_core.hpp"
8
#include "convert.hpp"
9
10
/****************************************************************************************\
11
* Generalized split/merge: mixing channels *
12
\****************************************************************************************/
13
14
namespace cv
15
{
16
17
template<typename T> static void
18
mixChannels_( const T** src, const int* sdelta,
19
T** dst, const int* ddelta,
20
int len, int npairs )
21
{
22
int i, k;
23
for( k = 0; k < npairs; k++ )
24
{
25
const T* s = src[k];
26
T* d = dst[k];
27
int ds = sdelta[k], dd = ddelta[k];
28
if( s )
29
{
30
for( i = 0; i <= len - 2; i += 2, s += ds*2, d += dd*2 )
31
{
32
T t0 = s[0], t1 = s[ds];
33
d[0] = t0; d[dd] = t1;
34
}
35
if( i < len )
36
d[0] = s[0];
37
}
38
else
39
{
40
for( i = 0; i <= len - 2; i += 2, d += dd*2 )
41
d[0] = d[dd] = 0;
42
if( i < len )
43
d[0] = 0;
44
}
45
}
46
}
47
48
49
static void mixChannels8u( const uchar** src, const int* sdelta,
50
uchar** dst, const int* ddelta,
51
int len, int npairs )
52
{
53
mixChannels_(src, sdelta, dst, ddelta, len, npairs);
54
}
55
56
static void mixChannels16u( const ushort** src, const int* sdelta,
57
ushort** dst, const int* ddelta,
58
int len, int npairs )
59
{
60
mixChannels_(src, sdelta, dst, ddelta, len, npairs);
61
}
62
63
static void mixChannels32s( const int** src, const int* sdelta,
64
int** dst, const int* ddelta,
65
int len, int npairs )
66
{
67
mixChannels_(src, sdelta, dst, ddelta, len, npairs);
68
}
69
70
static void mixChannels64s( const int64** src, const int* sdelta,
71
int64** dst, const int* ddelta,
72
int len, int npairs )
73
{
74
mixChannels_(src, sdelta, dst, ddelta, len, npairs);
75
}
76
77
typedef void (*MixChannelsFunc)( const uchar** src, const int* sdelta,
78
uchar** dst, const int* ddelta, int len, int npairs );
79
80
static MixChannelsFunc getMixchFunc(int depth)
81
{
82
static MixChannelsFunc mixchTab[] =
83
{
84
(MixChannelsFunc)mixChannels8u, (MixChannelsFunc)mixChannels8u, (MixChannelsFunc)mixChannels16u,
85
(MixChannelsFunc)mixChannels16u, (MixChannelsFunc)mixChannels32s, (MixChannelsFunc)mixChannels32s,
86
(MixChannelsFunc)mixChannels64s, 0
87
};
88
89
return mixchTab[depth];
90
}
91
92
} // cv::
93
94
95
void cv::mixChannels( const Mat* src, size_t nsrcs, Mat* dst, size_t ndsts, const int* fromTo, size_t npairs )
96
{
97
CV_INSTRUMENT_REGION();
98
99
if( npairs == 0 )
100
return;
101
CV_Assert( src && nsrcs > 0 && dst && ndsts > 0 && fromTo && npairs > 0 );
102
103
size_t i, j, k, esz1 = dst[0].elemSize1();
104
int depth = dst[0].depth();
105
106
AutoBuffer<uchar> buf((nsrcs + ndsts + 1)*(sizeof(Mat*) + sizeof(uchar*)) + npairs*(sizeof(uchar*)*2 + sizeof(int)*6));
107
const Mat** arrays = (const Mat**)(uchar*)buf.data();
108
uchar** ptrs = (uchar**)(arrays + nsrcs + ndsts);
109
const uchar** srcs = (const uchar**)(ptrs + nsrcs + ndsts + 1);
110
uchar** dsts = (uchar**)(srcs + npairs);
111
int* tab = (int*)(dsts + npairs);
112
int *sdelta = (int*)(tab + npairs*4), *ddelta = sdelta + npairs;
113
114
for( i = 0; i < nsrcs; i++ )
115
arrays[i] = &src[i];
116
for( i = 0; i < ndsts; i++ )
117
arrays[i + nsrcs] = &dst[i];
118
ptrs[nsrcs + ndsts] = 0;
119
120
for( i = 0; i < npairs; i++ )
121
{
122
int i0 = fromTo[i*2], i1 = fromTo[i*2+1];
123
if( i0 >= 0 )
124
{
125
for( j = 0; j < nsrcs; i0 -= src[j].channels(), j++ )
126
if( i0 < src[j].channels() )
127
break;
128
CV_Assert(j < nsrcs && src[j].depth() == depth);
129
tab[i*4] = (int)j; tab[i*4+1] = (int)(i0*esz1);
130
sdelta[i] = src[j].channels();
131
}
132
else
133
{
134
tab[i*4] = (int)(nsrcs + ndsts); tab[i*4+1] = 0;
135
sdelta[i] = 0;
136
}
137
138
for( j = 0; j < ndsts; i1 -= dst[j].channels(), j++ )
139
if( i1 < dst[j].channels() )
140
break;
141
CV_Assert(i1 >= 0 && j < ndsts && dst[j].depth() == depth);
142
tab[i*4+2] = (int)(j + nsrcs); tab[i*4+3] = (int)(i1*esz1);
143
ddelta[i] = dst[j].channels();
144
}
145
146
NAryMatIterator it(arrays, ptrs, (int)(nsrcs + ndsts));
147
int total = (int)it.size, blocksize = std::min(total, (int)((BLOCK_SIZE + esz1-1)/esz1));
148
MixChannelsFunc func = getMixchFunc(depth);
149
150
for( i = 0; i < it.nplanes; i++, ++it )
151
{
152
for( k = 0; k < npairs; k++ )
153
{
154
srcs[k] = ptrs[tab[k*4]] + tab[k*4+1];
155
dsts[k] = ptrs[tab[k*4+2]] + tab[k*4+3];
156
}
157
158
for( int t = 0; t < total; t += blocksize )
159
{
160
int bsz = std::min(total - t, blocksize);
161
func( srcs, sdelta, dsts, ddelta, bsz, (int)npairs );
162
163
if( t + blocksize < total )
164
for( k = 0; k < npairs; k++ )
165
{
166
srcs[k] += blocksize*sdelta[k]*esz1;
167
dsts[k] += blocksize*ddelta[k]*esz1;
168
}
169
}
170
}
171
}
172
173
#ifdef HAVE_OPENCL
174
175
namespace cv {
176
177
static void getUMatIndex(const std::vector<UMat> & um, int cn, int & idx, int & cnidx)
178
{
179
int totalChannels = 0;
180
for (size_t i = 0, size = um.size(); i < size; ++i)
181
{
182
int ccn = um[i].channels();
183
totalChannels += ccn;
184
185
if (totalChannels == cn)
186
{
187
idx = (int)(i + 1);
188
cnidx = 0;
189
return;
190
}
191
else if (totalChannels > cn)
192
{
193
idx = (int)i;
194
cnidx = i == 0 ? cn : (cn - totalChannels + ccn);
195
return;
196
}
197
}
198
199
idx = cnidx = -1;
200
}
201
202
static bool ocl_mixChannels(InputArrayOfArrays _src, InputOutputArrayOfArrays _dst,
203
const int* fromTo, size_t npairs)
204
{
205
std::vector<UMat> src, dst;
206
_src.getUMatVector(src);
207
_dst.getUMatVector(dst);
208
209
size_t nsrc = src.size(), ndst = dst.size();
210
CV_Assert(nsrc > 0 && ndst > 0);
211
212
Size size = src[0].size();
213
int depth = src[0].depth(), esz = CV_ELEM_SIZE(depth),
214
rowsPerWI = ocl::Device::getDefault().isIntel() ? 4 : 1;
215
216
for (size_t i = 1, ssize = src.size(); i < ssize; ++i)
217
CV_Assert(src[i].size() == size && src[i].depth() == depth);
218
for (size_t i = 0, dsize = dst.size(); i < dsize; ++i)
219
CV_Assert(dst[i].size() == size && dst[i].depth() == depth);
220
221
String declsrc, decldst, declproc, declcn, indexdecl;
222
std::vector<UMat> srcargs(npairs), dstargs(npairs);
223
224
for (size_t i = 0; i < npairs; ++i)
225
{
226
int scn = fromTo[i<<1], dcn = fromTo[(i<<1) + 1];
227
int src_idx, src_cnidx, dst_idx, dst_cnidx;
228
229
getUMatIndex(src, scn, src_idx, src_cnidx);
230
getUMatIndex(dst, dcn, dst_idx, dst_cnidx);
231
232
CV_Assert(dst_idx >= 0 && src_idx >= 0);
233
234
srcargs[i] = src[src_idx];
235
srcargs[i].offset += src_cnidx * esz;
236
237
dstargs[i] = dst[dst_idx];
238
dstargs[i].offset += dst_cnidx * esz;
239
240
declsrc += format("DECLARE_INPUT_MAT(%zu)", i);
241
decldst += format("DECLARE_OUTPUT_MAT(%zu)", i);
242
indexdecl += format("DECLARE_INDEX(%zu)", i);
243
declproc += format("PROCESS_ELEM(%zu)", i);
244
declcn += format(" -D scn%zu=%d -D dcn%zu=%d", i, src[src_idx].channels(), i, dst[dst_idx].channels());
245
}
246
247
ocl::Kernel k("mixChannels", ocl::core::mixchannels_oclsrc,
248
format("-D T=%s -D DECLARE_INPUT_MAT_N=%s -D DECLARE_OUTPUT_MAT_N=%s"
249
" -D PROCESS_ELEM_N=%s -D DECLARE_INDEX_N=%s%s",
250
ocl::memopTypeToStr(depth), declsrc.c_str(), decldst.c_str(),
251
declproc.c_str(), indexdecl.c_str(), declcn.c_str()));
252
if (k.empty())
253
return false;
254
255
int argindex = 0;
256
for (size_t i = 0; i < npairs; ++i)
257
argindex = k.set(argindex, ocl::KernelArg::ReadOnlyNoSize(srcargs[i]));
258
for (size_t i = 0; i < npairs; ++i)
259
argindex = k.set(argindex, ocl::KernelArg::WriteOnlyNoSize(dstargs[i]));
260
argindex = k.set(argindex, size.height);
261
argindex = k.set(argindex, size.width);
262
k.set(argindex, rowsPerWI);
263
264
size_t globalsize[2] = { (size_t)size.width, ((size_t)size.height + rowsPerWI - 1) / rowsPerWI };
265
return k.run(2, globalsize, NULL, false);
266
}
267
268
}
269
270
#endif
271
272
void cv::mixChannels(InputArrayOfArrays src, InputOutputArrayOfArrays dst,
273
const int* fromTo, size_t npairs)
274
{
275
CV_INSTRUMENT_REGION();
276
277
if (npairs == 0 || fromTo == NULL)
278
return;
279
280
CV_OCL_RUN(dst.isUMatVector(),
281
ocl_mixChannels(src, dst, fromTo, npairs))
282
283
bool src_is_mat = src.kind() != _InputArray::STD_VECTOR_MAT &&
284
src.kind() != _InputArray::STD_ARRAY_MAT &&
285
src.kind() != _InputArray::STD_VECTOR_VECTOR &&
286
src.kind() != _InputArray::STD_VECTOR_UMAT;
287
bool dst_is_mat = dst.kind() != _InputArray::STD_VECTOR_MAT &&
288
dst.kind() != _InputArray::STD_ARRAY_MAT &&
289
dst.kind() != _InputArray::STD_VECTOR_VECTOR &&
290
dst.kind() != _InputArray::STD_VECTOR_UMAT;
291
int i;
292
int nsrc = src_is_mat ? 1 : (int)src.total();
293
int ndst = dst_is_mat ? 1 : (int)dst.total();
294
295
CV_Assert(nsrc > 0 && ndst > 0);
296
cv::AutoBuffer<Mat> _buf(nsrc + ndst);
297
Mat* buf = _buf.data();
298
for( i = 0; i < nsrc; i++ )
299
buf[i] = src.getMat(src_is_mat ? -1 : i);
300
for( i = 0; i < ndst; i++ )
301
buf[nsrc + i] = dst.getMat(dst_is_mat ? -1 : i);
302
mixChannels(&buf[0], nsrc, &buf[nsrc], ndst, fromTo, npairs);
303
}
304
305
void cv::mixChannels(InputArrayOfArrays src, InputOutputArrayOfArrays dst,
306
const std::vector<int>& fromTo)
307
{
308
CV_INSTRUMENT_REGION();
309
310
if (fromTo.empty())
311
return;
312
313
CV_OCL_RUN(dst.isUMatVector(),
314
ocl_mixChannels(src, dst, &fromTo[0], fromTo.size()>>1))
315
316
bool src_is_mat = src.kind() != _InputArray::STD_VECTOR_MAT &&
317
src.kind() != _InputArray::STD_ARRAY_MAT &&
318
src.kind() != _InputArray::STD_VECTOR_VECTOR &&
319
src.kind() != _InputArray::STD_VECTOR_UMAT;
320
bool dst_is_mat = dst.kind() != _InputArray::STD_VECTOR_MAT &&
321
dst.kind() != _InputArray::STD_ARRAY_MAT &&
322
dst.kind() != _InputArray::STD_VECTOR_VECTOR &&
323
dst.kind() != _InputArray::STD_VECTOR_UMAT;
324
int i;
325
int nsrc = src_is_mat ? 1 : (int)src.total();
326
int ndst = dst_is_mat ? 1 : (int)dst.total();
327
328
CV_Assert(fromTo.size()%2 == 0 && nsrc > 0 && ndst > 0);
329
cv::AutoBuffer<Mat> _buf(nsrc + ndst);
330
Mat* buf = _buf.data();
331
for( i = 0; i < nsrc; i++ )
332
buf[i] = src.getMat(src_is_mat ? -1 : i);
333
for( i = 0; i < ndst; i++ )
334
buf[nsrc + i] = dst.getMat(dst_is_mat ? -1 : i);
335
mixChannels(&buf[0], nsrc, &buf[nsrc], ndst, &fromTo[0], fromTo.size()/2);
336
}
337
338
#ifdef HAVE_IPP
339
340
namespace cv
341
{
342
static bool ipp_extractChannel(const Mat &src, Mat &dst, int channel)
343
{
344
#ifdef HAVE_IPP_IW_LL
345
CV_INSTRUMENT_REGION_IPP();
346
347
int srcChannels = src.channels();
348
int dstChannels = dst.channels();
349
350
if(src.dims != dst.dims)
351
return false;
352
353
if(src.dims <= 2)
354
{
355
IppiSize size = ippiSize(src.size());
356
357
return CV_INSTRUMENT_FUN_IPP(llwiCopyChannel, src.ptr(), (int)src.step, srcChannels, channel, dst.ptr(), (int)dst.step, dstChannels, 0, size, (int)src.elemSize1()) >= 0;
358
}
359
else
360
{
361
const Mat *arrays[] = {&dst, NULL};
362
uchar *ptrs[2] = {NULL};
363
NAryMatIterator it(arrays, ptrs);
364
365
IppiSize size = {(int)it.size, 1};
366
367
for( size_t i = 0; i < it.nplanes; i++, ++it )
368
{
369
if(CV_INSTRUMENT_FUN_IPP(llwiCopyChannel, ptrs[0], 0, srcChannels, channel, ptrs[1], 0, dstChannels, 0, size, (int)src.elemSize1()) < 0)
370
return false;
371
}
372
return true;
373
}
374
#else
375
CV_UNUSED(src); CV_UNUSED(dst); CV_UNUSED(channel);
376
return false;
377
#endif
378
}
379
380
static bool ipp_insertChannel(const Mat &src, Mat &dst, int channel)
381
{
382
#ifdef HAVE_IPP_IW_LL
383
CV_INSTRUMENT_REGION_IPP();
384
385
int srcChannels = src.channels();
386
int dstChannels = dst.channels();
387
388
if(src.dims != dst.dims)
389
return false;
390
391
if(src.dims <= 2)
392
{
393
IppiSize size = ippiSize(src.size());
394
395
return CV_INSTRUMENT_FUN_IPP(llwiCopyChannel, src.ptr(), (int)src.step, srcChannels, 0, dst.ptr(), (int)dst.step, dstChannels, channel, size, (int)src.elemSize1()) >= 0;
396
}
397
else
398
{
399
const Mat *arrays[] = {&dst, NULL};
400
uchar *ptrs[2] = {NULL};
401
NAryMatIterator it(arrays, ptrs);
402
403
IppiSize size = {(int)it.size, 1};
404
405
for( size_t i = 0; i < it.nplanes; i++, ++it )
406
{
407
if(CV_INSTRUMENT_FUN_IPP(llwiCopyChannel, ptrs[0], 0, srcChannels, 0, ptrs[1], 0, dstChannels, channel, size, (int)src.elemSize1()) < 0)
408
return false;
409
}
410
return true;
411
}
412
#else
413
CV_UNUSED(src); CV_UNUSED(dst); CV_UNUSED(channel);
414
return false;
415
#endif
416
}
417
}
418
#endif
419
420
void cv::extractChannel(InputArray _src, OutputArray _dst, int coi)
421
{
422
CV_INSTRUMENT_REGION();
423
424
int type = _src.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
425
CV_Assert( 0 <= coi && coi < cn );
426
int ch[] = { coi, 0 };
427
428
#ifdef HAVE_OPENCL
429
if (ocl::isOpenCLActivated() && _src.dims() <= 2 && _dst.isUMat())
430
{
431
UMat src = _src.getUMat();
432
_dst.create(src.dims, &src.size[0], depth);
433
UMat dst = _dst.getUMat();
434
mixChannels(std::vector<UMat>(1, src), std::vector<UMat>(1, dst), ch, 1);
435
return;
436
}
437
#endif
438
439
Mat src = _src.getMat();
440
_dst.create(src.dims, &src.size[0], depth);
441
Mat dst = _dst.getMat();
442
443
CV_IPP_RUN_FAST(ipp_extractChannel(src, dst, coi))
444
445
mixChannels(&src, 1, &dst, 1, ch, 1);
446
}
447
448
void cv::insertChannel(InputArray _src, InputOutputArray _dst, int coi)
449
{
450
CV_INSTRUMENT_REGION();
451
452
int stype = _src.type(), sdepth = CV_MAT_DEPTH(stype), scn = CV_MAT_CN(stype);
453
int dtype = _dst.type(), ddepth = CV_MAT_DEPTH(dtype), dcn = CV_MAT_CN(dtype);
454
CV_Assert( _src.sameSize(_dst) && sdepth == ddepth );
455
CV_Assert( 0 <= coi && coi < dcn && scn == 1 );
456
457
int ch[] = { 0, coi };
458
#ifdef HAVE_OPENCL
459
if (ocl::isOpenCLActivated() && _src.dims() <= 2 && _dst.isUMat())
460
{
461
UMat src = _src.getUMat(), dst = _dst.getUMat();
462
mixChannels(std::vector<UMat>(1, src), std::vector<UMat>(1, dst), ch, 1);
463
return;
464
}
465
#endif
466
467
Mat src = _src.getMat(), dst = _dst.getMat();
468
469
CV_IPP_RUN_FAST(ipp_insertChannel(src, dst, coi))
470
471
mixChannels(&src, 1, &dst, 1, ch, 1);
472
}
473
474