40e5b51b93f00c9e91e6594e532a82f8808c40b4
[profile/ivi/opencv.git] / modules / core / src / copy.cpp
1 /*M///////////////////////////////////////////////////////////////////////////////////////
2 //
3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4 //
5 //  By downloading, copying, installing or using the software you agree to this license.
6 //  If you do not agree to this license, do not download, install,
7 //  copy or use the software.
8 //
9 //                           License Agreement
10 //                For Open Source Computer Vision Library
11 //
12 // Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
13 // Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved.
14 // Third party copyrights are property of their respective owners.
15 //
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
18 //
19 //   * Redistribution's of source code must retain the above copyright notice,
20 //     this list of conditions and the following disclaimer.
21 //
22 //   * Redistribution's in binary form must reproduce the above copyright notice,
23 //     this list of conditions and the following disclaimer in the documentation
24 //     and/or other materials provided with the distribution.
25 //
26 //   * The name of the copyright holders may not be used to endorse or promote products
27 //     derived from this software without specific prior written permission.
28 //
29 // This software is provided by the copyright holders and contributors "as is" and
30 // any express or implied warranties, including, but not limited to, the implied
31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
32 // In no event shall the Intel Corporation or contributors be liable for any direct,
33 // indirect, incidental, special, exemplary, or consequential damages
34 // (including, but not limited to, procurement of substitute goods or services;
35 // loss of use, data, or profits; or business interruption) however caused
36 // and on any theory of liability, whether in contract, strict liability,
37 // or tort (including negligence or otherwise) arising in any way out of
38 // the use of this software, even if advised of the possibility of such damage.
39 //
40 //M*/
41
42 /* ////////////////////////////////////////////////////////////////////
43 //
44 //  Mat basic operations: Copy, Set
45 //
46 // */
47
48 #include "precomp.hpp"
49 #include "opencl_kernels.hpp"
50
51 namespace cv
52 {
53
54 template<typename T> static void
55 copyMask_(const uchar* _src, size_t sstep, const uchar* mask, size_t mstep, uchar* _dst, size_t dstep, Size size)
56 {
57     for( ; size.height--; mask += mstep, _src += sstep, _dst += dstep )
58     {
59         const T* src = (const T*)_src;
60         T* dst = (T*)_dst;
61         int x = 0;
62          #if CV_ENABLE_UNROLLED
63         for( ; x <= size.width - 4; x += 4 )
64         {
65             if( mask[x] )
66                 dst[x] = src[x];
67             if( mask[x+1] )
68                 dst[x+1] = src[x+1];
69             if( mask[x+2] )
70                 dst[x+2] = src[x+2];
71             if( mask[x+3] )
72                 dst[x+3] = src[x+3];
73         }
74         #endif
75         for( ; x < size.width; x++ )
76             if( mask[x] )
77                 dst[x] = src[x];
78     }
79 }
80
81 template<> void
82 copyMask_<uchar>(const uchar* _src, size_t sstep, const uchar* mask, size_t mstep, uchar* _dst, size_t dstep, Size size)
83 {
84 #if defined HAVE_IPP && !defined HAVE_IPP_ICV_ONLY
85     if (ippiCopy_8u_C1MR(_src, (int)sstep, _dst, (int)dstep, ippiSize(size), mask, (int)mstep) >= 0)
86         return;
87 #endif
88
89     for( ; size.height--; mask += mstep, _src += sstep, _dst += dstep )
90     {
91         const uchar* src = (const uchar*)_src;
92         uchar* dst = (uchar*)_dst;
93         int x = 0;
94         #if CV_SSE4_2
95         if(USE_SSE4_2)//
96         {
97             __m128i zero = _mm_setzero_si128 ();
98
99              for( ; x <= size.width - 16; x += 16 )
100              {
101                  const __m128i rSrc = _mm_lddqu_si128((const __m128i*)(src+x));
102                  __m128i _mask = _mm_lddqu_si128((const __m128i*)(mask+x));
103                  __m128i rDst = _mm_lddqu_si128((__m128i*)(dst+x));
104                  __m128i _negMask = _mm_cmpeq_epi8(_mask, zero);
105                  rDst = _mm_blendv_epi8(rSrc, rDst, _negMask);
106                  _mm_storeu_si128((__m128i*)(dst + x), rDst);
107              }
108         }
109         #endif
110         for( ; x < size.width; x++ )
111             if( mask[x] )
112                 dst[x] = src[x];
113     }
114 }
115
116 template<> void
117 copyMask_<ushort>(const uchar* _src, size_t sstep, const uchar* mask, size_t mstep, uchar* _dst, size_t dstep, Size size)
118 {
119 #if defined HAVE_IPP && !defined HAVE_IPP_ICV_ONLY
120     if (ippiCopy_16u_C1MR((const Ipp16u *)_src, (int)sstep, (Ipp16u *)_dst, (int)dstep, ippiSize(size), mask, (int)mstep) >= 0)
121         return;
122 #endif
123
124     for( ; size.height--; mask += mstep, _src += sstep, _dst += dstep )
125     {
126         const ushort* src = (const ushort*)_src;
127         ushort* dst = (ushort*)_dst;
128         int x = 0;
129         #if CV_SSE4_2
130         if(USE_SSE4_2)//
131         {
132             __m128i zero = _mm_setzero_si128 ();
133             for( ; x <= size.width - 8; x += 8 )
134             {
135                  const __m128i rSrc =_mm_lddqu_si128((const __m128i*)(src+x));
136                  __m128i _mask = _mm_loadl_epi64((const __m128i*)(mask+x));
137                  _mask = _mm_unpacklo_epi8(_mask, _mask);
138                  __m128i rDst = _mm_lddqu_si128((const __m128i*)(dst+x));
139                  __m128i _negMask = _mm_cmpeq_epi8(_mask, zero);
140                  rDst = _mm_blendv_epi8(rSrc, rDst, _negMask);
141                  _mm_storeu_si128((__m128i*)(dst + x), rDst);
142              }
143         }
144         #endif
145         for( ; x < size.width; x++ )
146             if( mask[x] )
147                 dst[x] = src[x];
148     }
149 }
150
151 static void
152 copyMaskGeneric(const uchar* _src, size_t sstep, const uchar* mask, size_t mstep, uchar* _dst, size_t dstep, Size size, void* _esz)
153 {
154     size_t k, esz = *(size_t*)_esz;
155     for( ; size.height--; mask += mstep, _src += sstep, _dst += dstep )
156     {
157         const uchar* src = _src;
158         uchar* dst = _dst;
159         int x = 0;
160         for( ; x < size.width; x++, src += esz, dst += esz )
161         {
162             if( !mask[x] )
163                 continue;
164             for( k = 0; k < esz; k++ )
165                 dst[k] = src[k];
166         }
167     }
168 }
169
170
171 #define DEF_COPY_MASK(suffix, type) \
172 static void copyMask##suffix(const uchar* src, size_t sstep, const uchar* mask, size_t mstep, \
173                              uchar* dst, size_t dstep, Size size, void*) \
174 { \
175     copyMask_<type>(src, sstep, mask, mstep, dst, dstep, size); \
176 }
177
178 #if defined HAVE_IPP && !defined HAVE_IPP_ICV_ONLY
179 #define DEF_COPY_MASK_F(suffix, type, ippfavor, ipptype) \
180 static void copyMask##suffix(const uchar* src, size_t sstep, const uchar* mask, size_t mstep, \
181                              uchar* dst, size_t dstep, Size size, void*) \
182 { \
183     if (ippiCopy_##ippfavor((const ipptype *)src, (int)sstep, (ipptype *)dst, (int)dstep, ippiSize(size), (const Ipp8u *)mask, (int)mstep) >= 0) \
184         return; \
185     copyMask_<type>(src, sstep, mask, mstep, dst, dstep, size); \
186 }
187 #else
188 #define DEF_COPY_MASK_F(suffix, type, ippfavor, ipptype) \
189 static void copyMask##suffix(const uchar* src, size_t sstep, const uchar* mask, size_t mstep, \
190                              uchar* dst, size_t dstep, Size size, void*) \
191 { \
192     copyMask_<type>(src, sstep, mask, mstep, dst, dstep, size); \
193 }
194 #endif
195
196
197 DEF_COPY_MASK(8u, uchar)
198 DEF_COPY_MASK(16u, ushort)
199 DEF_COPY_MASK_F(8uC3, Vec3b, 8u_C3MR, Ipp8u)
200 DEF_COPY_MASK_F(32s, int, 32s_C1MR, Ipp32s)
201 DEF_COPY_MASK_F(16uC3, Vec3s, 16u_C3MR, Ipp16u)
202 DEF_COPY_MASK(32sC2, Vec2i)
203 DEF_COPY_MASK_F(32sC3, Vec3i, 32s_C3MR, Ipp32s)
204 DEF_COPY_MASK_F(32sC4, Vec4i, 32s_C4MR, Ipp32s)
205 DEF_COPY_MASK(32sC6, Vec6i)
206 DEF_COPY_MASK(32sC8, Vec8i)
207
208 BinaryFunc copyMaskTab[] =
209 {
210     0,
211     copyMask8u,
212     copyMask16u,
213     copyMask8uC3,
214     copyMask32s,
215     0,
216     copyMask16uC3,
217     0,
218     copyMask32sC2,
219     0, 0, 0,
220     copyMask32sC3,
221     0, 0, 0,
222     copyMask32sC4,
223     0, 0, 0, 0, 0, 0, 0,
224     copyMask32sC6,
225     0, 0, 0, 0, 0, 0, 0,
226     copyMask32sC8
227 };
228
229 BinaryFunc getCopyMaskFunc(size_t esz)
230 {
231     return esz <= 32 && copyMaskTab[esz] ? copyMaskTab[esz] : copyMaskGeneric;
232 }
233
234 /* dst = src */
235 void Mat::copyTo( OutputArray _dst ) const
236 {
237     int dtype = _dst.type();
238     if( _dst.fixedType() && dtype != type() )
239     {
240         CV_Assert( channels() == CV_MAT_CN(dtype) );
241         convertTo( _dst, dtype );
242         return;
243     }
244
245     if( empty() )
246     {
247         _dst.release();
248         return;
249     }
250
251     if( _dst.isUMat() )
252     {
253         _dst.create( dims, size.p, type() );
254         UMat dst = _dst.getUMat();
255
256         size_t i, sz[CV_MAX_DIM], dstofs[CV_MAX_DIM], esz = elemSize();
257         for( i = 0; i < (size_t)dims; i++ )
258             sz[i] = size.p[i];
259         sz[dims-1] *= esz;
260         dst.ndoffset(dstofs);
261         dstofs[dims-1] *= esz;
262         dst.u->currAllocator->upload(dst.u, data, dims, sz, dstofs, dst.step.p, step.p);
263         return;
264     }
265
266     if( dims <= 2 )
267     {
268         _dst.create( rows, cols, type() );
269         Mat dst = _dst.getMat();
270         if( data == dst.data )
271             return;
272
273         if( rows > 0 && cols > 0 )
274         {
275             const uchar* sptr = data;
276             uchar* dptr = dst.data;
277
278             Size sz = getContinuousSize(*this, dst);
279             size_t len = sz.width*elemSize();
280
281 #if defined HAVE_IPP && !defined HAVE_IPP_ICV_ONLY
282             if (ippiCopy_8u_C1R(sptr, (int)step, dptr, (int)dst.step, ippiSize((int)len, sz.height)) >= 0)
283                 return;
284 #endif
285
286             for( ; sz.height--; sptr += step, dptr += dst.step )
287                 memcpy( dptr, sptr, len );
288         }
289         return;
290     }
291
292     _dst.create( dims, size, type() );
293     Mat dst = _dst.getMat();
294     if( data == dst.data )
295         return;
296
297     if( total() != 0 )
298     {
299         const Mat* arrays[] = { this, &dst };
300         uchar* ptrs[2];
301         NAryMatIterator it(arrays, ptrs, 2);
302         size_t sz = it.size*elemSize();
303
304         for( size_t i = 0; i < it.nplanes; i++, ++it )
305             memcpy(ptrs[1], ptrs[0], sz);
306     }
307 }
308
309 void Mat::copyTo( OutputArray _dst, InputArray _mask ) const
310 {
311     Mat mask = _mask.getMat();
312     if( !mask.data )
313     {
314         copyTo(_dst);
315         return;
316     }
317
318     int cn = channels(), mcn = mask.channels();
319     CV_Assert( mask.depth() == CV_8U && (mcn == 1 || mcn == cn) );
320     bool colorMask = mcn > 1;
321
322     size_t esz = colorMask ? elemSize1() : elemSize();
323     BinaryFunc copymask = getCopyMaskFunc(esz);
324
325     uchar* data0 = _dst.getMat().data;
326     _dst.create( dims, size, type() );
327     Mat dst = _dst.getMat();
328
329     if( dst.data != data0 ) // do not leave dst uninitialized
330         dst = Scalar(0);
331
332     if( dims <= 2 )
333     {
334         CV_Assert( size() == mask.size() );
335         Size sz = getContinuousSize(*this, dst, mask, mcn);
336         copymask(data, step, mask.data, mask.step, dst.data, dst.step, sz, &esz);
337         return;
338     }
339
340     const Mat* arrays[] = { this, &dst, &mask, 0 };
341     uchar* ptrs[3];
342     NAryMatIterator it(arrays, ptrs);
343     Size sz((int)(it.size*mcn), 1);
344
345     for( size_t i = 0; i < it.nplanes; i++, ++it )
346         copymask(ptrs[0], 0, ptrs[2], 0, ptrs[1], 0, sz, &esz);
347 }
348
349 Mat& Mat::operator = (const Scalar& s)
350 {
351     const Mat* arrays[] = { this };
352     uchar* dptr;
353     NAryMatIterator it(arrays, &dptr, 1);
354     size_t elsize = it.size*elemSize();
355     const int64* is = (const int64*)&s.val[0];
356
357     if( is[0] == 0 && is[1] == 0 && is[2] == 0 && is[3] == 0 )
358     {
359 #if defined HAVE_IPP && !defined HAVE_IPP_ICV_ONLY
360         if (dims <= 2 || isContinuous())
361         {
362             IppiSize roisize = { cols, rows };
363             if (isContinuous())
364             {
365                 roisize.width = (int)total();
366                 roisize.height = 1;
367
368                 if (ippsZero_8u(data, roisize.width * elemSize()) >= 0)
369                     return *this;
370             }
371             roisize.width *= elemSize();
372
373             if (ippiSet_8u_C1R(0, data, (int)step, roisize) >= 0)
374                 return *this;
375         }
376 #endif
377
378         for( size_t i = 0; i < it.nplanes; i++, ++it )
379             memset( dptr, 0, elsize );
380     }
381     else
382     {
383         if( it.nplanes > 0 )
384         {
385             double scalar[12];
386             scalarToRawData(s, scalar, type(), 12);
387             size_t blockSize = 12*elemSize1();
388
389             for( size_t j = 0; j < elsize; j += blockSize )
390             {
391                 size_t sz = MIN(blockSize, elsize - j);
392                 memcpy( dptr + j, scalar, sz );
393             }
394         }
395
396         for( size_t i = 1; i < it.nplanes; i++ )
397         {
398             ++it;
399             memcpy( dptr, data, elsize );
400         }
401     }
402     return *this;
403 }
404
405
406 Mat& Mat::setTo(InputArray _value, InputArray _mask)
407 {
408     if( empty() )
409         return *this;
410
411     Mat value = _value.getMat(), mask = _mask.getMat();
412
413     CV_Assert( checkScalar(value, type(), _value.kind(), _InputArray::MAT ));
414     CV_Assert( mask.empty() || (mask.type() == CV_8U && size == mask.size) );
415
416 #if defined HAVE_IPP && !defined HAVE_IPP_ICV_ONLY
417     if (!mask.empty() && (dims <= 2 || (isContinuous() && mask.isContinuous())))
418     {
419         uchar buf[32];
420         convertAndUnrollScalar( value, type(), buf, 1 );
421
422         int cn = channels(), depth0 = depth();
423         IppStatus status = (IppStatus)-1;
424         IppiSize roisize = { cols, rows };
425         int mstep = (int)mask.step, dstep = (int)step;
426
427         if (isContinuous() && mask.isContinuous())
428         {
429             roisize.width = (int)total();
430             roisize.height = 1;
431         }
432
433         if (cn == 1)
434         {
435             if (depth0 == CV_8U)
436                 status = ippiSet_8u_C1MR(*(Ipp8u *)buf, (Ipp8u *)data, dstep, roisize, mask.data, mstep);
437             else if (depth0 == CV_16U)
438                 status = ippiSet_16u_C1MR(*(Ipp16u *)buf, (Ipp16u *)data, dstep, roisize, mask.data, mstep);
439             else if (depth0 == CV_16S)
440                 status = ippiSet_16s_C1MR(*(Ipp16s *)buf, (Ipp16s *)data, dstep, roisize, mask.data, mstep);
441             else if (depth0 == CV_32S)
442                 status = ippiSet_32s_C1MR(*(Ipp32s *)buf, (Ipp32s *)data, dstep, roisize, mask.data, mstep);
443             else if (depth0 == CV_32F)
444                 status = ippiSet_32f_C1MR(*(Ipp32f *)buf, (Ipp32f *)data, dstep, roisize, mask.data, mstep);
445         }
446         else if (cn == 3 || cn == 3)
447         {
448 #define IPP_SET(ippfavor, ippcn) \
449     do \
450     { \
451         typedef Ipp##ippfavor ipptype; \
452         ipptype ippvalue[4] = { ((ipptype *)buf)[0], ((ipptype *)buf)[1], ((ipptype *)buf)[2], ((ipptype *)buf)[4] }; \
453         status = ippiSet_##ippfavor##_C##ippcn##MR(ippvalue, (ipptype *)data, dstep, roisize, mask.data, mstep); \
454     } while ((void)0, 0)
455
456 #define IPP_SET_CN(ippcn) \
457     do \
458     { \
459         if (cn == ippcn) \
460         { \
461             if (depth0 == CV_8U) \
462                 IPP_SET(8u, ippcn); \
463             else if (depth0 == CV_16U) \
464                 IPP_SET(16u, ippcn); \
465             else if (depth0 == CV_16S) \
466                 IPP_SET(16s, ippcn); \
467             else if (depth0 == CV_32S) \
468                 IPP_SET(32s, ippcn); \
469             else if (depth0 == CV_32F) \
470                 IPP_SET(32f, ippcn); \
471         } \
472     } while ((void)0, 0)
473
474             IPP_SET_CN(3);
475             IPP_SET_CN(4);
476
477 #undef IPP_SET_CN
478 #undef IPP_SET
479         }
480
481         if (status >= 0)
482             return *this;
483     }
484 #endif
485
486     size_t esz = elemSize();
487     BinaryFunc copymask = getCopyMaskFunc(esz);
488
489     const Mat* arrays[] = { this, !mask.empty() ? &mask : 0, 0 };
490     uchar* ptrs[2]={0,0};
491     NAryMatIterator it(arrays, ptrs);
492     int totalsz = (int)it.size, blockSize0 = std::min(totalsz, (int)((BLOCK_SIZE + esz-1)/esz));
493     AutoBuffer<uchar> _scbuf(blockSize0*esz + 32);
494     uchar* scbuf = alignPtr((uchar*)_scbuf, (int)sizeof(double));
495     convertAndUnrollScalar( value, type(), scbuf, blockSize0 );
496
497     for( size_t i = 0; i < it.nplanes; i++, ++it )
498     {
499         for( int j = 0; j < totalsz; j += blockSize0 )
500         {
501             Size sz(std::min(blockSize0, totalsz - j), 1);
502             size_t blockSize = sz.width*esz;
503             if( ptrs[1] )
504             {
505                 copymask(scbuf, 0, ptrs[1], 0, ptrs[0], 0, sz, &esz);
506                 ptrs[1] += sz.width;
507             }
508             else
509                 memcpy(ptrs[0], scbuf, blockSize);
510             ptrs[0] += blockSize;
511         }
512     }
513     return *this;
514 }
515
516
517 static void
518 flipHoriz( const uchar* src, size_t sstep, uchar* dst, size_t dstep, Size size, size_t esz )
519 {
520     int i, j, limit = (int)(((size.width + 1)/2)*esz);
521     AutoBuffer<int> _tab(size.width*esz);
522     int* tab = _tab;
523
524     for( i = 0; i < size.width; i++ )
525         for( size_t k = 0; k < esz; k++ )
526             tab[i*esz + k] = (int)((size.width - i - 1)*esz + k);
527
528     for( ; size.height--; src += sstep, dst += dstep )
529     {
530         for( i = 0; i < limit; i++ )
531         {
532             j = tab[i];
533             uchar t0 = src[i], t1 = src[j];
534             dst[i] = t1; dst[j] = t0;
535         }
536     }
537 }
538
539 static void
540 flipVert( const uchar* src0, size_t sstep, uchar* dst0, size_t dstep, Size size, size_t esz )
541 {
542     const uchar* src1 = src0 + (size.height - 1)*sstep;
543     uchar* dst1 = dst0 + (size.height - 1)*dstep;
544     size.width *= (int)esz;
545
546     for( int y = 0; y < (size.height + 1)/2; y++, src0 += sstep, src1 -= sstep,
547                                                   dst0 += dstep, dst1 -= dstep )
548     {
549         int i = 0;
550         if( ((size_t)src0|(size_t)dst0|(size_t)src1|(size_t)dst1) % sizeof(int) == 0 )
551         {
552             for( ; i <= size.width - 16; i += 16 )
553             {
554                 int t0 = ((int*)(src0 + i))[0];
555                 int t1 = ((int*)(src1 + i))[0];
556
557                 ((int*)(dst0 + i))[0] = t1;
558                 ((int*)(dst1 + i))[0] = t0;
559
560                 t0 = ((int*)(src0 + i))[1];
561                 t1 = ((int*)(src1 + i))[1];
562
563                 ((int*)(dst0 + i))[1] = t1;
564                 ((int*)(dst1 + i))[1] = t0;
565
566                 t0 = ((int*)(src0 + i))[2];
567                 t1 = ((int*)(src1 + i))[2];
568
569                 ((int*)(dst0 + i))[2] = t1;
570                 ((int*)(dst1 + i))[2] = t0;
571
572                 t0 = ((int*)(src0 + i))[3];
573                 t1 = ((int*)(src1 + i))[3];
574
575                 ((int*)(dst0 + i))[3] = t1;
576                 ((int*)(dst1 + i))[3] = t0;
577             }
578
579             for( ; i <= size.width - 4; i += 4 )
580             {
581                 int t0 = ((int*)(src0 + i))[0];
582                 int t1 = ((int*)(src1 + i))[0];
583
584                 ((int*)(dst0 + i))[0] = t1;
585                 ((int*)(dst1 + i))[0] = t0;
586             }
587         }
588
589         for( ; i < size.width; i++ )
590         {
591             uchar t0 = src0[i];
592             uchar t1 = src1[i];
593
594             dst0[i] = t1;
595             dst1[i] = t0;
596         }
597     }
598 }
599
600 #ifdef HAVE_OPENCL
601
602 enum { FLIP_COLS = 1 << 0, FLIP_ROWS = 1 << 1, FLIP_BOTH = FLIP_ROWS | FLIP_COLS };
603
604 static bool ocl_flip(InputArray _src, OutputArray _dst, int flipCode )
605 {
606     CV_Assert(flipCode >= - 1 && flipCode <= 1);
607     int type = _src.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type), flipType;
608
609     if (cn > 4)
610         return false;
611
612     const char * kernelName;
613     if (flipCode == 0)
614         kernelName = "arithm_flip_rows", flipType = FLIP_ROWS;
615     else if (flipCode > 0)
616         kernelName = "arithm_flip_cols", flipType = FLIP_COLS;
617     else
618         kernelName = "arithm_flip_rows_cols", flipType = FLIP_BOTH;
619
620     ocl::Kernel k(kernelName, ocl::core::flip_oclsrc,
621         format( "-D T=%s -D T1=%s -D cn=%d", ocl::memopTypeToStr(type),
622                 ocl::memopTypeToStr(depth), cn));
623     if (k.empty())
624         return false;
625
626     Size size = _src.size();
627     _dst.create(size, type);
628     UMat src = _src.getUMat(), dst = _dst.getUMat();
629
630     int cols = size.width, rows = size.height;
631     cols = flipType == FLIP_COLS ? (cols + 1) >> 1 : cols;
632     rows = flipType & FLIP_ROWS ? (rows + 1) >> 1 : rows;
633
634     k.args(ocl::KernelArg::ReadOnlyNoSize(src),
635            ocl::KernelArg::WriteOnly(dst), rows, cols);
636
637     size_t maxWorkGroupSize = ocl::Device::getDefault().maxWorkGroupSize();
638     CV_Assert(maxWorkGroupSize % 4 == 0);
639     size_t globalsize[2] = { cols, rows }, localsize[2] = { maxWorkGroupSize / 4, 4 };
640     return k.run(2, globalsize, flipType == FLIP_COLS ? localsize : NULL, false);
641 }
642
643 #endif
644
645 void flip( InputArray _src, OutputArray _dst, int flip_mode )
646 {
647     CV_Assert( _src.dims() <= 2 );
648     Size size = _src.size();
649
650     if (flip_mode < 0)
651     {
652         if (size.width == 1)
653             flip_mode = 0;
654         if (size.height == 1)
655             flip_mode = 1;
656     }
657
658     if ((size.width == 1 && flip_mode > 0) ||
659         (size.height == 1 && flip_mode == 0) ||
660         (size.height == 1 && size.width == 1 && flip_mode < 0))
661     {
662         return _src.copyTo(_dst);
663     }
664
665     CV_OCL_RUN( _dst.isUMat(), ocl_flip(_src, _dst, flip_mode))
666
667     Mat src = _src.getMat();
668     int type = src.type();
669     _dst.create( size, type );
670     Mat dst = _dst.getMat();
671     size_t esz = CV_ELEM_SIZE(type);
672
673 #if defined HAVE_IPP && !defined HAVE_IPP_ICV_ONLY
674     typedef IppStatus (CV_STDCALL * ippiMirror)(const void * pSrc, int srcStep, void * pDst, int dstStep, IppiSize roiSize, IppiAxis flip);
675     typedef IppStatus (CV_STDCALL * ippiMirrorI)(const void * pSrcDst, int srcDstStep, IppiSize roiSize, IppiAxis flip);
676     ippiMirror ippFunc = 0;
677     ippiMirrorI ippFuncI = 0;
678
679     if (src.data == dst.data)
680     {
681         ippFuncI =
682             type == CV_8UC1 ? (ippiMirrorI)ippiMirror_8u_C1IR :
683             type == CV_8UC3 ? (ippiMirrorI)ippiMirror_8u_C3IR :
684             type == CV_8UC4 ? (ippiMirrorI)ippiMirror_8u_C4IR :
685             type == CV_16UC1 ? (ippiMirrorI)ippiMirror_16u_C1IR :
686             type == CV_16UC3 ? (ippiMirrorI)ippiMirror_16u_C3IR :
687             type == CV_16UC4 ? (ippiMirrorI)ippiMirror_16u_C4IR :
688             type == CV_16SC1 ? (ippiMirrorI)ippiMirror_16s_C1IR :
689             type == CV_16SC3 ? (ippiMirrorI)ippiMirror_16s_C3IR :
690             type == CV_16SC4 ? (ippiMirrorI)ippiMirror_16s_C4IR :
691             type == CV_32SC1 ? (ippiMirrorI)ippiMirror_32s_C1IR :
692             type == CV_32SC3 ? (ippiMirrorI)ippiMirror_32s_C3IR :
693             type == CV_32SC4 ? (ippiMirrorI)ippiMirror_32s_C4IR :
694             type == CV_32FC1 ? (ippiMirrorI)ippiMirror_32f_C1IR :
695             type == CV_32FC3 ? (ippiMirrorI)ippiMirror_32f_C3IR :
696             type == CV_32FC4 ? (ippiMirrorI)ippiMirror_32f_C4IR : 0;
697     }
698     else
699     {
700         ippFunc =
701             type == CV_8UC1 ? (ippiMirror)ippiMirror_8u_C1R :
702             type == CV_8UC3 ? (ippiMirror)ippiMirror_8u_C3R :
703             type == CV_8UC4 ? (ippiMirror)ippiMirror_8u_C4R :
704             type == CV_16UC1 ? (ippiMirror)ippiMirror_16u_C1R :
705             type == CV_16UC3 ? (ippiMirror)ippiMirror_16u_C3R :
706             type == CV_16UC4 ? (ippiMirror)ippiMirror_16u_C4R :
707             type == CV_16SC1 ? (ippiMirror)ippiMirror_16s_C1R :
708             type == CV_16SC3 ? (ippiMirror)ippiMirror_16s_C3R :
709             type == CV_16SC4 ? (ippiMirror)ippiMirror_16s_C4R :
710             type == CV_32SC1 ? (ippiMirror)ippiMirror_32s_C1R :
711             type == CV_32SC3 ? (ippiMirror)ippiMirror_32s_C3R :
712             type == CV_32SC4 ? (ippiMirror)ippiMirror_32s_C4R :
713             type == CV_32FC1 ? (ippiMirror)ippiMirror_32f_C1R :
714             type == CV_32FC3 ? (ippiMirror)ippiMirror_32f_C3R :
715             type == CV_32FC4 ? (ippiMirror)ippiMirror_32f_C4R : 0;
716     }
717     IppiAxis axis = flip_mode == 0 ? ippAxsHorizontal :
718         flip_mode > 0 ? ippAxsVertical : ippAxsBoth;
719     IppiSize roisize = { dst.cols, dst.rows };
720
721     if (ippFunc != 0)
722     {
723         if (ippFunc(src.data, (int)src.step, dst.data, (int)dst.step, ippiSize(src.cols, src.rows), axis) >= 0)
724             return;
725         setIppErrorStatus();
726     }
727     else if (ippFuncI != 0)
728     {
729         if (ippFuncI(dst.data, (int)dst.step, roisize, axis) >= 0)
730             return;
731         setIppErrorStatus();
732     }
733
734     if( flip_mode <= 0 )
735         flipVert( src.data, src.step, dst.data, dst.step, src.size(), esz );
736     else
737         flipHoriz( src.data, src.step, dst.data, dst.step, src.size(), esz );
738
739     if( flip_mode < 0 )
740         flipHoriz( dst.data, dst.step, dst.data, dst.step, dst.size(), esz );
741 }
742
743 #ifdef HAVE_OPENCL
744
745 static bool ocl_repeat(InputArray _src, int ny, int nx, OutputArray _dst)
746 {
747     UMat src = _src.getUMat(), dst = _dst.getUMat();
748
749     for (int y = 0; y < ny; ++y)
750         for (int x = 0; x < nx; ++x)
751         {
752             Rect roi(x * src.cols, y * src.rows, src.cols, src.rows);
753             UMat hdr(dst, roi);
754             src.copyTo(hdr);
755         }
756     return true;
757 }
758
759 #endif
760
761 void repeat(InputArray _src, int ny, int nx, OutputArray _dst)
762 {
763     CV_Assert( _src.dims() <= 2 );
764     CV_Assert( ny > 0 && nx > 0 );
765
766     Size ssize = _src.size();
767     _dst.create(ssize.height*ny, ssize.width*nx, _src.type());
768
769     CV_OCL_RUN(_dst.isUMat(),
770                ocl_repeat(_src, ny, nx, _dst))
771
772     Mat src = _src.getMat(), dst = _dst.getMat();
773     Size dsize = dst.size();
774     int esz = (int)src.elemSize();
775     int x, y;
776     ssize.width *= esz; dsize.width *= esz;
777
778     for( y = 0; y < ssize.height; y++ )
779     {
780         for( x = 0; x < dsize.width; x += ssize.width )
781             memcpy( dst.data + y*dst.step + x, src.data + y*src.step, ssize.width );
782     }
783
784     for( ; y < dsize.height; y++ )
785         memcpy( dst.data + y*dst.step, dst.data + (y - ssize.height)*dst.step, dsize.width );
786 }
787
788 Mat repeat(const Mat& src, int ny, int nx)
789 {
790     if( nx == 1 && ny == 1 )
791         return src;
792     Mat dst;
793     repeat(src, ny, nx, dst);
794     return dst;
795 }
796
797
798 } // cv
799
800
801 /*
802  Various border types, image boundaries are denoted with '|'
803
804  * BORDER_REPLICATE:     aaaaaa|abcdefgh|hhhhhhh
805  * BORDER_REFLECT:       fedcba|abcdefgh|hgfedcb
806  * BORDER_REFLECT_101:   gfedcb|abcdefgh|gfedcba
807  * BORDER_WRAP:          cdefgh|abcdefgh|abcdefg
808  * BORDER_CONSTANT:      iiiiii|abcdefgh|iiiiiii  with some specified 'i'
809  */
810 int cv::borderInterpolate( int p, int len, int borderType )
811 {
812     if( (unsigned)p < (unsigned)len )
813         ;
814     else if( borderType == BORDER_REPLICATE )
815         p = p < 0 ? 0 : len - 1;
816     else if( borderType == BORDER_REFLECT || borderType == BORDER_REFLECT_101 )
817     {
818         int delta = borderType == BORDER_REFLECT_101;
819         if( len == 1 )
820             return 0;
821         do
822         {
823             if( p < 0 )
824                 p = -p - 1 + delta;
825             else
826                 p = len - 1 - (p - len) - delta;
827         }
828         while( (unsigned)p >= (unsigned)len );
829     }
830     else if( borderType == BORDER_WRAP )
831     {
832         CV_Assert(len > 0);
833         if( p < 0 )
834             p -= ((p-len+1)/len)*len;
835         if( p >= len )
836             p %= len;
837     }
838     else if( borderType == BORDER_CONSTANT )
839         p = -1;
840     else
841         CV_Error( CV_StsBadArg, "Unknown/unsupported border type" );
842     return p;
843 }
844
845 namespace
846 {
847
848 void copyMakeBorder_8u( const uchar* src, size_t srcstep, cv::Size srcroi,
849                         uchar* dst, size_t dststep, cv::Size dstroi,
850                         int top, int left, int cn, int borderType )
851 {
852     const int isz = (int)sizeof(int);
853     int i, j, k, elemSize = 1;
854     bool intMode = false;
855
856     if( (cn | srcstep | dststep | (size_t)src | (size_t)dst) % isz == 0 )
857     {
858         cn /= isz;
859         elemSize = isz;
860         intMode = true;
861     }
862
863     cv::AutoBuffer<int> _tab((dstroi.width - srcroi.width)*cn);
864     int* tab = _tab;
865     int right = dstroi.width - srcroi.width - left;
866     int bottom = dstroi.height - srcroi.height - top;
867
868     for( i = 0; i < left; i++ )
869     {
870         j = cv::borderInterpolate(i - left, srcroi.width, borderType)*cn;
871         for( k = 0; k < cn; k++ )
872             tab[i*cn + k] = j + k;
873     }
874
875     for( i = 0; i < right; i++ )
876     {
877         j = cv::borderInterpolate(srcroi.width + i, srcroi.width, borderType)*cn;
878         for( k = 0; k < cn; k++ )
879             tab[(i+left)*cn + k] = j + k;
880     }
881
882     srcroi.width *= cn;
883     dstroi.width *= cn;
884     left *= cn;
885     right *= cn;
886
887     uchar* dstInner = dst + dststep*top + left*elemSize;
888
889     for( i = 0; i < srcroi.height; i++, dstInner += dststep, src += srcstep )
890     {
891         if( dstInner != src )
892             memcpy(dstInner, src, srcroi.width*elemSize);
893
894         if( intMode )
895         {
896             const int* isrc = (int*)src;
897             int* idstInner = (int*)dstInner;
898             for( j = 0; j < left; j++ )
899                 idstInner[j - left] = isrc[tab[j]];
900             for( j = 0; j < right; j++ )
901                 idstInner[j + srcroi.width] = isrc[tab[j + left]];
902         }
903         else
904         {
905             for( j = 0; j < left; j++ )
906                 dstInner[j - left] = src[tab[j]];
907             for( j = 0; j < right; j++ )
908                 dstInner[j + srcroi.width] = src[tab[j + left]];
909         }
910     }
911
912     dstroi.width *= elemSize;
913     dst += dststep*top;
914
915     for( i = 0; i < top; i++ )
916     {
917         j = cv::borderInterpolate(i - top, srcroi.height, borderType);
918         memcpy(dst + (i - top)*dststep, dst + j*dststep, dstroi.width);
919     }
920
921     for( i = 0; i < bottom; i++ )
922     {
923         j = cv::borderInterpolate(i + srcroi.height, srcroi.height, borderType);
924         memcpy(dst + (i + srcroi.height)*dststep, dst + j*dststep, dstroi.width);
925     }
926 }
927
928
929 void copyMakeConstBorder_8u( const uchar* src, size_t srcstep, cv::Size srcroi,
930                              uchar* dst, size_t dststep, cv::Size dstroi,
931                              int top, int left, int cn, const uchar* value )
932 {
933     int i, j;
934     cv::AutoBuffer<uchar> _constBuf(dstroi.width*cn);
935     uchar* constBuf = _constBuf;
936     int right = dstroi.width - srcroi.width - left;
937     int bottom = dstroi.height - srcroi.height - top;
938
939     for( i = 0; i < dstroi.width; i++ )
940     {
941         for( j = 0; j < cn; j++ )
942             constBuf[i*cn + j] = value[j];
943     }
944
945     srcroi.width *= cn;
946     dstroi.width *= cn;
947     left *= cn;
948     right *= cn;
949
950     uchar* dstInner = dst + dststep*top + left;
951
952     for( i = 0; i < srcroi.height; i++, dstInner += dststep, src += srcstep )
953     {
954         if( dstInner != src )
955             memcpy( dstInner, src, srcroi.width );
956         memcpy( dstInner - left, constBuf, left );
957         memcpy( dstInner + srcroi.width, constBuf, right );
958     }
959
960     dst += dststep*top;
961
962     for( i = 0; i < top; i++ )
963         memcpy(dst + (i - top)*dststep, constBuf, dstroi.width);
964
965     for( i = 0; i < bottom; i++ )
966         memcpy(dst + (i + srcroi.height)*dststep, constBuf, dstroi.width);
967 }
968
969 }
970
971 #ifdef HAVE_OPENCL
972
973 namespace cv {
974
975 static bool ocl_copyMakeBorder( InputArray _src, OutputArray _dst, int top, int bottom,
976                                 int left, int right, int borderType, const Scalar& value )
977 {
978     int type = _src.type(), cn = CV_MAT_CN(type), depth = CV_MAT_DEPTH(type);
979     bool isolated = (borderType & BORDER_ISOLATED) != 0;
980     borderType &= ~cv::BORDER_ISOLATED;
981
982     if ( !(borderType == BORDER_CONSTANT || borderType == BORDER_REPLICATE || borderType == BORDER_REFLECT ||
983            borderType == BORDER_WRAP || borderType == BORDER_REFLECT_101) ||
984          cn > 4)
985         return false;
986
987     const char * const borderMap[] = { "BORDER_CONSTANT", "BORDER_REPLICATE", "BORDER_REFLECT", "BORDER_WRAP", "BORDER_REFLECT_101" };
988     int scalarcn = cn == 3 ? 4 : cn;
989     int sctype = CV_MAKETYPE(depth, scalarcn);
990     String buildOptions = format(
991             "-D T=%s -D %s "
992             "-D T1=%s -D cn=%d -D ST=%s",
993             ocl::memopTypeToStr(type), borderMap[borderType],
994             ocl::memopTypeToStr(depth), cn, ocl::memopTypeToStr(sctype)
995     );
996
997     ocl::Kernel k("copyMakeBorder", ocl::core::copymakeborder_oclsrc, buildOptions);
998     if (k.empty())
999         return false;
1000
1001     UMat src = _src.getUMat();
1002     if( src.isSubmatrix() && !isolated )
1003     {
1004         Size wholeSize;
1005         Point ofs;
1006         src.locateROI(wholeSize, ofs);
1007         int dtop = std::min(ofs.y, top);
1008         int dbottom = std::min(wholeSize.height - src.rows - ofs.y, bottom);
1009         int dleft = std::min(ofs.x, left);
1010         int dright = std::min(wholeSize.width - src.cols - ofs.x, right);
1011         src.adjustROI(dtop, dbottom, dleft, dright);
1012         top -= dtop;
1013         left -= dleft;
1014         bottom -= dbottom;
1015         right -= dright;
1016     }
1017
1018     _dst.create(src.rows + top + bottom, src.cols + left + right, type);
1019     UMat dst = _dst.getUMat();
1020
1021     if (top == 0 && left == 0 && bottom == 0 && right == 0)
1022     {
1023         if(src.u != dst.u || src.step != dst.step)
1024             src.copyTo(dst);
1025         return true;
1026     }
1027
1028     k.args(ocl::KernelArg::ReadOnly(src), ocl::KernelArg::WriteOnly(dst),
1029            top, left, ocl::KernelArg::Constant(Mat(1, 1, sctype, value)));
1030
1031     size_t globalsize[2] = { dst.cols, dst.rows };
1032     return k.run(2, globalsize, NULL, false);
1033 }
1034
1035 }
1036
1037 #endif
1038
1039 void cv::copyMakeBorder( InputArray _src, OutputArray _dst, int top, int bottom,
1040                          int left, int right, int borderType, const Scalar& value )
1041 {
1042     CV_Assert( top >= 0 && bottom >= 0 && left >= 0 && right >= 0 );
1043
1044     CV_OCL_RUN(_dst.isUMat() && _src.dims() <= 2,
1045                ocl_copyMakeBorder(_src, _dst, top, bottom, left, right, borderType, value))
1046
1047     Mat src = _src.getMat();
1048
1049     if( src.isSubmatrix() && (borderType & BORDER_ISOLATED) == 0 )
1050     {
1051         Size wholeSize;
1052         Point ofs;
1053         src.locateROI(wholeSize, ofs);
1054         int dtop = std::min(ofs.y, top);
1055         int dbottom = std::min(wholeSize.height - src.rows - ofs.y, bottom);
1056         int dleft = std::min(ofs.x, left);
1057         int dright = std::min(wholeSize.width - src.cols - ofs.x, right);
1058         src.adjustROI(dtop, dbottom, dleft, dright);
1059         top -= dtop;
1060         left -= dleft;
1061         bottom -= dbottom;
1062         right -= dright;
1063     }
1064
1065     _dst.create( src.rows + top + bottom, src.cols + left + right, src.type() );
1066     Mat dst = _dst.getMat();
1067
1068     if(top == 0 && left == 0 && bottom == 0 && right == 0)
1069     {
1070         if(src.data != dst.data || src.step != dst.step)
1071             src.copyTo(dst);
1072         return;
1073     }
1074
1075     borderType &= ~BORDER_ISOLATED;
1076
1077     if( borderType != BORDER_CONSTANT )
1078         copyMakeBorder_8u( src.data, src.step, src.size(),
1079                            dst.data, dst.step, dst.size(),
1080                            top, left, (int)src.elemSize(), borderType );
1081     else
1082     {
1083         int cn = src.channels(), cn1 = cn;
1084         AutoBuffer<double> buf(cn);
1085         if( cn > 4 )
1086         {
1087             CV_Assert( value[0] == value[1] && value[0] == value[2] && value[0] == value[3] );
1088             cn1 = 1;
1089         }
1090         scalarToRawData(value, buf, CV_MAKETYPE(src.depth(), cn1), cn);
1091         copyMakeConstBorder_8u( src.data, src.step, src.size(),
1092                                 dst.data, dst.step, dst.size(),
1093                                 top, left, (int)src.elemSize(), (uchar*)(double*)buf );
1094     }
1095 }
1096
1097 /* dst = src */
1098 CV_IMPL void
1099 cvCopy( const void* srcarr, void* dstarr, const void* maskarr )
1100 {
1101     if( CV_IS_SPARSE_MAT(srcarr) && CV_IS_SPARSE_MAT(dstarr))
1102     {
1103         CV_Assert( maskarr == 0 );
1104         CvSparseMat* src1 = (CvSparseMat*)srcarr;
1105         CvSparseMat* dst1 = (CvSparseMat*)dstarr;
1106         CvSparseMatIterator iterator;
1107         CvSparseNode* node;
1108
1109         dst1->dims = src1->dims;
1110         memcpy( dst1->size, src1->size, src1->dims*sizeof(src1->size[0]));
1111         dst1->valoffset = src1->valoffset;
1112         dst1->idxoffset = src1->idxoffset;
1113         cvClearSet( dst1->heap );
1114
1115         if( src1->heap->active_count >= dst1->hashsize*CV_SPARSE_HASH_RATIO )
1116         {
1117             cvFree( &dst1->hashtable );
1118             dst1->hashsize = src1->hashsize;
1119             dst1->hashtable =
1120                 (void**)cvAlloc( dst1->hashsize*sizeof(dst1->hashtable[0]));
1121         }
1122
1123         memset( dst1->hashtable, 0, dst1->hashsize*sizeof(dst1->hashtable[0]));
1124
1125         for( node = cvInitSparseMatIterator( src1, &iterator );
1126              node != 0; node = cvGetNextSparseNode( &iterator ))
1127         {
1128             CvSparseNode* node_copy = (CvSparseNode*)cvSetNew( dst1->heap );
1129             int tabidx = node->hashval & (dst1->hashsize - 1);
1130             memcpy( node_copy, node, dst1->heap->elem_size );
1131             node_copy->next = (CvSparseNode*)dst1->hashtable[tabidx];
1132             dst1->hashtable[tabidx] = node_copy;
1133         }
1134         return;
1135     }
1136     cv::Mat src = cv::cvarrToMat(srcarr, false, true, 1), dst = cv::cvarrToMat(dstarr, false, true, 1);
1137     CV_Assert( src.depth() == dst.depth() && src.size == dst.size );
1138
1139     int coi1 = 0, coi2 = 0;
1140     if( CV_IS_IMAGE(srcarr) )
1141         coi1 = cvGetImageCOI((const IplImage*)srcarr);
1142     if( CV_IS_IMAGE(dstarr) )
1143         coi2 = cvGetImageCOI((const IplImage*)dstarr);
1144
1145     if( coi1 || coi2 )
1146     {
1147         CV_Assert( (coi1 != 0 || src.channels() == 1) &&
1148             (coi2 != 0 || dst.channels() == 1) );
1149
1150         int pair[] = { std::max(coi1-1, 0), std::max(coi2-1, 0) };
1151         cv::mixChannels( &src, 1, &dst, 1, pair, 1 );
1152         return;
1153     }
1154     else
1155         CV_Assert( src.channels() == dst.channels() );
1156
1157     if( !maskarr )
1158         src.copyTo(dst);
1159     else
1160         src.copyTo(dst, cv::cvarrToMat(maskarr));
1161 }
1162
1163 CV_IMPL void
1164 cvSet( void* arr, CvScalar value, const void* maskarr )
1165 {
1166     cv::Mat m = cv::cvarrToMat(arr);
1167     if( !maskarr )
1168         m = value;
1169     else
1170         m.setTo(cv::Scalar(value), cv::cvarrToMat(maskarr));
1171 }
1172
1173 CV_IMPL void
1174 cvSetZero( CvArr* arr )
1175 {
1176     if( CV_IS_SPARSE_MAT(arr) )
1177     {
1178         CvSparseMat* mat1 = (CvSparseMat*)arr;
1179         cvClearSet( mat1->heap );
1180         if( mat1->hashtable )
1181             memset( mat1->hashtable, 0, mat1->hashsize*sizeof(mat1->hashtable[0]));
1182         return;
1183     }
1184     cv::Mat m = cv::cvarrToMat(arr);
1185     m = cv::Scalar(0);
1186 }
1187
1188 CV_IMPL void
1189 cvFlip( const CvArr* srcarr, CvArr* dstarr, int flip_mode )
1190 {
1191     cv::Mat src = cv::cvarrToMat(srcarr);
1192     cv::Mat dst;
1193
1194     if (!dstarr)
1195       dst = src;
1196     else
1197       dst = cv::cvarrToMat(dstarr);
1198
1199     CV_Assert( src.type() == dst.type() && src.size() == dst.size() );
1200     cv::flip( src, dst, flip_mode );
1201 }
1202
1203 CV_IMPL void
1204 cvRepeat( const CvArr* srcarr, CvArr* dstarr )
1205 {
1206     cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr);
1207     CV_Assert( src.type() == dst.type() &&
1208         dst.rows % src.rows == 0 && dst.cols % src.cols == 0 );
1209     cv::repeat(src, dst.rows/src.rows, dst.cols/src.cols, dst);
1210 }
1211
1212 /* End of file. */