6f7b61ac7e49e62537d75d99e002c6ed2f499368
[platform/upstream/opencv.git] / modules / core / src / split.cpp
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
9 namespace cv { namespace hal {
10
11 #if CV_SIMD
12 template<typename T, typename VecT> static void
13 vecsplit_( const T* src, T** dst, int len, int cn )
14 {
15     int i;
16     T* dst0 = dst[0];
17     T* dst1 = dst[1];
18
19     const int VECSZ = VecT::nlanes;
20     if( cn == 2 )
21     {
22         for( i = 0; i < len; i += VECSZ )
23         {
24             i = std::min( len - VECSZ, i );
25             VecT a, b;
26             v_load_deinterleave(src + i*cn, a, b);
27             v_store(dst0 + i, a);
28             v_store(dst1 + i, b);
29         }
30     }
31     else if( cn == 3 )
32     {
33         T* dst2 = dst[2];
34         for( i = 0; i < len; i += VECSZ )
35         {
36             i = std::min( len - VECSZ, i );
37             VecT a, b, c;
38             v_load_deinterleave(src + i*cn, a, b, c);
39             v_store(dst0 + i, a);
40             v_store(dst1 + i, b);
41             v_store(dst2 + i, c);
42         }
43     }
44     else
45     {
46         CV_Assert( cn == 4 );
47         T* dst2 = dst[2];
48         T* dst3 = dst[3];
49         for( i = 0; i < len; i += VECSZ )
50         {
51             i = std::min( len - VECSZ, i );
52             VecT a, b, c, d;
53             v_load_deinterleave(src + i*cn, a, b, c, d);
54             v_store(dst0 + i, a);
55             v_store(dst1 + i, b);
56             v_store(dst2 + i, c);
57             v_store(dst3 + i, d);
58         }
59     }
60     vx_cleanup();
61 }
62 #endif
63
64 template<typename T> static void
65 split_( const T* src, T** dst, int len, int cn )
66 {
67     int k = cn % 4 ? cn % 4 : 4;
68     int i, j;
69     if( k == 1 )
70     {
71         T* dst0 = dst[0];
72
73         if(cn == 1)
74         {
75             memcpy(dst0, src, len * sizeof(T));
76         }
77         else
78         {
79             for( i = 0, j = 0 ; i < len; i++, j += cn )
80                 dst0[i] = src[j];
81         }
82     }
83     else if( k == 2 )
84     {
85         T *dst0 = dst[0], *dst1 = dst[1];
86         i = j = 0;
87
88         for( ; i < len; i++, j += cn )
89         {
90             dst0[i] = src[j];
91             dst1[i] = src[j+1];
92         }
93     }
94     else if( k == 3 )
95     {
96         T *dst0 = dst[0], *dst1 = dst[1], *dst2 = dst[2];
97         i = j = 0;
98
99         for( ; i < len; i++, j += cn )
100         {
101             dst0[i] = src[j];
102             dst1[i] = src[j+1];
103             dst2[i] = src[j+2];
104         }
105     }
106     else
107     {
108         T *dst0 = dst[0], *dst1 = dst[1], *dst2 = dst[2], *dst3 = dst[3];
109         i = j = 0;
110
111         for( ; i < len; i++, j += cn )
112         {
113             dst0[i] = src[j]; dst1[i] = src[j+1];
114             dst2[i] = src[j+2]; dst3[i] = src[j+3];
115         }
116     }
117
118     for( ; k < cn; k += 4 )
119     {
120         T *dst0 = dst[k], *dst1 = dst[k+1], *dst2 = dst[k+2], *dst3 = dst[k+3];
121         for( i = 0, j = k; i < len; i++, j += cn )
122         {
123             dst0[i] = src[j]; dst1[i] = src[j+1];
124             dst2[i] = src[j+2]; dst3[i] = src[j+3];
125         }
126     }
127 }
128
129 void split8u(const uchar* src, uchar** dst, int len, int cn )
130 {
131     CALL_HAL(split8u, cv_hal_split8u, src,dst, len, cn)
132
133 #if CV_SIMD
134     if( len >= v_uint8::nlanes && 2 <= cn && cn <= 4 )
135         vecsplit_<uchar, v_uint8>(src, dst, len, cn);
136     else
137 #endif
138         split_(src, dst, len, cn);
139 }
140
141 void split16u(const ushort* src, ushort** dst, int len, int cn )
142 {
143     CALL_HAL(split16u, cv_hal_split16u, src,dst, len, cn)
144 #if CV_SIMD
145     if( len >= v_uint16::nlanes && 2 <= cn && cn <= 4 )
146         vecsplit_<ushort, v_uint16>(src, dst, len, cn);
147     else
148 #endif
149         split_(src, dst, len, cn);
150 }
151
152 void split32s(const int* src, int** dst, int len, int cn )
153 {
154     CALL_HAL(split32s, cv_hal_split32s, src,dst, len, cn)
155 #if CV_SIMD
156     if( len >= v_uint32::nlanes && 2 <= cn && cn <= 4 )
157         vecsplit_<int, v_int32>(src, dst, len, cn);
158     else
159 #endif
160         split_(src, dst, len, cn);
161 }
162
163 void split64s(const int64* src, int64** dst, int len, int cn )
164 {
165     CALL_HAL(split64s, cv_hal_split64s, src,dst, len, cn)
166 #if CV_SIMD
167     if( len >= v_int64::nlanes && 2 <= cn && cn <= 4 )
168         vecsplit_<int64, v_int64>(src, dst, len, cn);
169     else
170 #endif
171         split_(src, dst, len, cn);
172 }
173
174 }} // cv::hal::
175
176 /****************************************************************************************\
177 *                                       split & merge                                    *
178 \****************************************************************************************/
179
180 typedef void (*SplitFunc)(const uchar* src, uchar** dst, int len, int cn);
181
182 static SplitFunc getSplitFunc(int depth)
183 {
184     static SplitFunc splitTab[] =
185     {
186         (SplitFunc)GET_OPTIMIZED(cv::hal::split8u), (SplitFunc)GET_OPTIMIZED(cv::hal::split8u), (SplitFunc)GET_OPTIMIZED(cv::hal::split16u), (SplitFunc)GET_OPTIMIZED(cv::hal::split16u),
187         (SplitFunc)GET_OPTIMIZED(cv::hal::split32s), (SplitFunc)GET_OPTIMIZED(cv::hal::split32s), (SplitFunc)GET_OPTIMIZED(cv::hal::split64s), 0
188     };
189
190     return splitTab[depth];
191 }
192
193 #ifdef HAVE_IPP
194
195 namespace cv {
196 static bool ipp_split(const Mat& src, Mat* mv, int channels)
197 {
198 #ifdef HAVE_IPP_IW
199     CV_INSTRUMENT_REGION_IPP()
200
201     if(channels != 3 && channels != 4)
202         return false;
203
204     if(src.dims <= 2)
205     {
206         IppiSize size       = ippiSize(src.size());
207         void    *dstPtrs[4] = {NULL};
208         size_t   dstStep    = mv[0].step;
209         for(int i = 0; i < channels; i++)
210         {
211             dstPtrs[i] = mv[i].ptr();
212             if(dstStep != mv[i].step)
213                 return false;
214         }
215
216         return CV_INSTRUMENT_FUN_IPP(llwiCopySplit, src.ptr(), (int)src.step, dstPtrs, (int)dstStep, size, (int)src.elemSize1(), channels, 0) >= 0;
217     }
218     else
219     {
220         const Mat *arrays[5] = {NULL};
221         uchar     *ptrs[5]   = {NULL};
222         arrays[0] = &src;
223
224         for(int i = 1; i < channels; i++)
225         {
226             arrays[i] = &mv[i-1];
227         }
228
229         NAryMatIterator it(arrays, ptrs);
230         IppiSize size = { (int)it.size, 1 };
231
232         for( size_t i = 0; i < it.nplanes; i++, ++it )
233         {
234             if(CV_INSTRUMENT_FUN_IPP(llwiCopySplit, ptrs[0], 0, (void**)&ptrs[1], 0, size, (int)src.elemSize1(), channels, 0) < 0)
235                 return false;
236         }
237         return true;
238     }
239 #else
240     CV_UNUSED(src); CV_UNUSED(mv); CV_UNUSED(channels);
241     return false;
242 #endif
243 }
244 }
245 #endif
246
247 void cv::split(const Mat& src, Mat* mv)
248 {
249     CV_INSTRUMENT_REGION()
250
251     int k, depth = src.depth(), cn = src.channels();
252     if( cn == 1 )
253     {
254         src.copyTo(mv[0]);
255         return;
256     }
257
258     for( k = 0; k < cn; k++ )
259     {
260         mv[k].create(src.dims, src.size, depth);
261     }
262
263     CV_IPP_RUN_FAST(ipp_split(src, mv, cn));
264
265     SplitFunc func = getSplitFunc(depth);
266     CV_Assert( func != 0 );
267
268     size_t esz = src.elemSize(), esz1 = src.elemSize1();
269     size_t blocksize0 = (BLOCK_SIZE + esz-1)/esz;
270     AutoBuffer<uchar> _buf((cn+1)*(sizeof(Mat*) + sizeof(uchar*)) + 16);
271     const Mat** arrays = (const Mat**)_buf.data();
272     uchar** ptrs = (uchar**)alignPtr(arrays + cn + 1, 16);
273
274     arrays[0] = &src;
275     for( k = 0; k < cn; k++ )
276     {
277         arrays[k+1] = &mv[k];
278     }
279
280     NAryMatIterator it(arrays, ptrs, cn+1);
281     size_t total = it.size;
282     size_t blocksize = std::min((size_t)CV_SPLIT_MERGE_MAX_BLOCK_SIZE(cn), cn <= 4 ? total : std::min(total, blocksize0));
283
284     for( size_t i = 0; i < it.nplanes; i++, ++it )
285     {
286         for( size_t j = 0; j < total; j += blocksize )
287         {
288             size_t bsz = std::min(total - j, blocksize);
289             func( ptrs[0], &ptrs[1], (int)bsz, cn );
290
291             if( j + blocksize < total )
292             {
293                 ptrs[0] += bsz*esz;
294                 for( k = 0; k < cn; k++ )
295                     ptrs[k+1] += bsz*esz1;
296             }
297         }
298     }
299 }
300
301 #ifdef HAVE_OPENCL
302
303 namespace cv {
304
305 static bool ocl_split( InputArray _m, OutputArrayOfArrays _mv )
306 {
307     int type = _m.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type),
308             rowsPerWI = ocl::Device::getDefault().isIntel() ? 4 : 1;
309
310     String dstargs, processelem, indexdecl;
311     for (int i = 0; i < cn; ++i)
312     {
313         dstargs += format("DECLARE_DST_PARAM(%d)", i);
314         indexdecl += format("DECLARE_INDEX(%d)", i);
315         processelem += format("PROCESS_ELEM(%d)", i);
316     }
317
318     ocl::Kernel k("split", ocl::core::split_merge_oclsrc,
319                   format("-D T=%s -D OP_SPLIT -D cn=%d -D DECLARE_DST_PARAMS=%s"
320                          " -D PROCESS_ELEMS_N=%s -D DECLARE_INDEX_N=%s",
321                          ocl::memopTypeToStr(depth), cn, dstargs.c_str(),
322                          processelem.c_str(), indexdecl.c_str()));
323     if (k.empty())
324         return false;
325
326     Size size = _m.size();
327     _mv.create(cn, 1, depth);
328     for (int i = 0; i < cn; ++i)
329         _mv.create(size, depth, i);
330
331     std::vector<UMat> dst;
332     _mv.getUMatVector(dst);
333
334     int argidx = k.set(0, ocl::KernelArg::ReadOnly(_m.getUMat()));
335     for (int i = 0; i < cn; ++i)
336         argidx = k.set(argidx, ocl::KernelArg::WriteOnlyNoSize(dst[i]));
337     k.set(argidx, rowsPerWI);
338
339     size_t globalsize[2] = { (size_t)size.width, ((size_t)size.height + rowsPerWI - 1) / rowsPerWI };
340     return k.run(2, globalsize, NULL, false);
341 }
342
343 }
344
345 #endif
346
347 void cv::split(InputArray _m, OutputArrayOfArrays _mv)
348 {
349     CV_INSTRUMENT_REGION()
350
351     CV_OCL_RUN(_m.dims() <= 2 && _mv.isUMatVector(),
352                ocl_split(_m, _mv))
353
354     Mat m = _m.getMat();
355     if( m.empty() )
356     {
357         _mv.release();
358         return;
359     }
360
361     CV_Assert( !_mv.fixedType() || _mv.empty() || _mv.type() == m.depth() );
362
363     int depth = m.depth(), cn = m.channels();
364     _mv.create(cn, 1, depth);
365     for (int i = 0; i < cn; ++i)
366         _mv.create(m.dims, m.size.p, depth, i);
367
368     std::vector<Mat> dst;
369     _mv.getMatVector(dst);
370
371     split(m, &dst[0]);
372 }