Merge pull request #10797 from mshabunin:split-convert

pull/10845/head
Alexander Alekhin 7 years ago
commit 17233c687e
  1. 472
      modules/core/src/channels.cpp
  2. 48
      modules/core/src/convert.avx2.cpp
  3. 5264
      modules/core/src/convert.cpp
  4. 52
      modules/core/src/convert.fp16.cpp
  5. 13
      modules/core/src/convert.hpp
  6. 48
      modules/core/src/convert.sse4_1.cpp
  7. 134
      modules/core/src/convert_c.cpp
  8. 1921
      modules/core/src/convert_scale.cpp
  9. 417
      modules/core/src/lut.cpp
  10. 277
      modules/core/src/merge.cpp
  11. 7
      modules/core/src/precomp.hpp
  12. 247
      modules/core/src/split.cpp

@ -0,0 +1,472 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html
#include "precomp.hpp"
#include "opencl_kernels_core.hpp"
#include "convert.hpp"
/****************************************************************************************\
* Generalized split/merge: mixing channels *
\****************************************************************************************/
namespace cv
{
template<typename T> static void
mixChannels_( const T** src, const int* sdelta,
T** dst, const int* ddelta,
int len, int npairs )
{
int i, k;
for( k = 0; k < npairs; k++ )
{
const T* s = src[k];
T* d = dst[k];
int ds = sdelta[k], dd = ddelta[k];
if( s )
{
for( i = 0; i <= len - 2; i += 2, s += ds*2, d += dd*2 )
{
T t0 = s[0], t1 = s[ds];
d[0] = t0; d[dd] = t1;
}
if( i < len )
d[0] = s[0];
}
else
{
for( i = 0; i <= len - 2; i += 2, d += dd*2 )
d[0] = d[dd] = 0;
if( i < len )
d[0] = 0;
}
}
}
static void mixChannels8u( const uchar** src, const int* sdelta,
uchar** dst, const int* ddelta,
int len, int npairs )
{
mixChannels_(src, sdelta, dst, ddelta, len, npairs);
}
static void mixChannels16u( const ushort** src, const int* sdelta,
ushort** dst, const int* ddelta,
int len, int npairs )
{
mixChannels_(src, sdelta, dst, ddelta, len, npairs);
}
static void mixChannels32s( const int** src, const int* sdelta,
int** dst, const int* ddelta,
int len, int npairs )
{
mixChannels_(src, sdelta, dst, ddelta, len, npairs);
}
static void mixChannels64s( const int64** src, const int* sdelta,
int64** dst, const int* ddelta,
int len, int npairs )
{
mixChannels_(src, sdelta, dst, ddelta, len, npairs);
}
typedef void (*MixChannelsFunc)( const uchar** src, const int* sdelta,
uchar** dst, const int* ddelta, int len, int npairs );
static MixChannelsFunc getMixchFunc(int depth)
{
static MixChannelsFunc mixchTab[] =
{
(MixChannelsFunc)mixChannels8u, (MixChannelsFunc)mixChannels8u, (MixChannelsFunc)mixChannels16u,
(MixChannelsFunc)mixChannels16u, (MixChannelsFunc)mixChannels32s, (MixChannelsFunc)mixChannels32s,
(MixChannelsFunc)mixChannels64s, 0
};
return mixchTab[depth];
}
} // cv::
void cv::mixChannels( const Mat* src, size_t nsrcs, Mat* dst, size_t ndsts, const int* fromTo, size_t npairs )
{
CV_INSTRUMENT_REGION()
if( npairs == 0 )
return;
CV_Assert( src && nsrcs > 0 && dst && ndsts > 0 && fromTo && npairs > 0 );
size_t i, j, k, esz1 = dst[0].elemSize1();
int depth = dst[0].depth();
AutoBuffer<uchar> buf((nsrcs + ndsts + 1)*(sizeof(Mat*) + sizeof(uchar*)) + npairs*(sizeof(uchar*)*2 + sizeof(int)*6));
const Mat** arrays = (const Mat**)(uchar*)buf;
uchar** ptrs = (uchar**)(arrays + nsrcs + ndsts);
const uchar** srcs = (const uchar**)(ptrs + nsrcs + ndsts + 1);
uchar** dsts = (uchar**)(srcs + npairs);
int* tab = (int*)(dsts + npairs);
int *sdelta = (int*)(tab + npairs*4), *ddelta = sdelta + npairs;
for( i = 0; i < nsrcs; i++ )
arrays[i] = &src[i];
for( i = 0; i < ndsts; i++ )
arrays[i + nsrcs] = &dst[i];
ptrs[nsrcs + ndsts] = 0;
for( i = 0; i < npairs; i++ )
{
int i0 = fromTo[i*2], i1 = fromTo[i*2+1];
if( i0 >= 0 )
{
for( j = 0; j < nsrcs; i0 -= src[j].channels(), j++ )
if( i0 < src[j].channels() )
break;
CV_Assert(j < nsrcs && src[j].depth() == depth);
tab[i*4] = (int)j; tab[i*4+1] = (int)(i0*esz1);
sdelta[i] = src[j].channels();
}
else
{
tab[i*4] = (int)(nsrcs + ndsts); tab[i*4+1] = 0;
sdelta[i] = 0;
}
for( j = 0; j < ndsts; i1 -= dst[j].channels(), j++ )
if( i1 < dst[j].channels() )
break;
CV_Assert(i1 >= 0 && j < ndsts && dst[j].depth() == depth);
tab[i*4+2] = (int)(j + nsrcs); tab[i*4+3] = (int)(i1*esz1);
ddelta[i] = dst[j].channels();
}
NAryMatIterator it(arrays, ptrs, (int)(nsrcs + ndsts));
int total = (int)it.size, blocksize = std::min(total, (int)((BLOCK_SIZE + esz1-1)/esz1));
MixChannelsFunc func = getMixchFunc(depth);
for( i = 0; i < it.nplanes; i++, ++it )
{
for( k = 0; k < npairs; k++ )
{
srcs[k] = ptrs[tab[k*4]] + tab[k*4+1];
dsts[k] = ptrs[tab[k*4+2]] + tab[k*4+3];
}
for( int t = 0; t < total; t += blocksize )
{
int bsz = std::min(total - t, blocksize);
func( srcs, sdelta, dsts, ddelta, bsz, (int)npairs );
if( t + blocksize < total )
for( k = 0; k < npairs; k++ )
{
srcs[k] += blocksize*sdelta[k]*esz1;
dsts[k] += blocksize*ddelta[k]*esz1;
}
}
}
}
#ifdef HAVE_OPENCL
namespace cv {
static void getUMatIndex(const std::vector<UMat> & um, int cn, int & idx, int & cnidx)
{
int totalChannels = 0;
for (size_t i = 0, size = um.size(); i < size; ++i)
{
int ccn = um[i].channels();
totalChannels += ccn;
if (totalChannels == cn)
{
idx = (int)(i + 1);
cnidx = 0;
return;
}
else if (totalChannels > cn)
{
idx = (int)i;
cnidx = i == 0 ? cn : (cn - totalChannels + ccn);
return;
}
}
idx = cnidx = -1;
}
static bool ocl_mixChannels(InputArrayOfArrays _src, InputOutputArrayOfArrays _dst,
const int* fromTo, size_t npairs)
{
std::vector<UMat> src, dst;
_src.getUMatVector(src);
_dst.getUMatVector(dst);
size_t nsrc = src.size(), ndst = dst.size();
CV_Assert(nsrc > 0 && ndst > 0);
Size size = src[0].size();
int depth = src[0].depth(), esz = CV_ELEM_SIZE(depth),
rowsPerWI = ocl::Device::getDefault().isIntel() ? 4 : 1;
for (size_t i = 1, ssize = src.size(); i < ssize; ++i)
CV_Assert(src[i].size() == size && src[i].depth() == depth);
for (size_t i = 0, dsize = dst.size(); i < dsize; ++i)
CV_Assert(dst[i].size() == size && dst[i].depth() == depth);
String declsrc, decldst, declproc, declcn, indexdecl;
std::vector<UMat> srcargs(npairs), dstargs(npairs);
for (size_t i = 0; i < npairs; ++i)
{
int scn = fromTo[i<<1], dcn = fromTo[(i<<1) + 1];
int src_idx, src_cnidx, dst_idx, dst_cnidx;
getUMatIndex(src, scn, src_idx, src_cnidx);
getUMatIndex(dst, dcn, dst_idx, dst_cnidx);
CV_Assert(dst_idx >= 0 && src_idx >= 0);
srcargs[i] = src[src_idx];
srcargs[i].offset += src_cnidx * esz;
dstargs[i] = dst[dst_idx];
dstargs[i].offset += dst_cnidx * esz;
declsrc += format("DECLARE_INPUT_MAT(%d)", i);
decldst += format("DECLARE_OUTPUT_MAT(%d)", i);
indexdecl += format("DECLARE_INDEX(%d)", i);
declproc += format("PROCESS_ELEM(%d)", i);
declcn += format(" -D scn%d=%d -D dcn%d=%d", i, src[src_idx].channels(), i, dst[dst_idx].channels());
}
ocl::Kernel k("mixChannels", ocl::core::mixchannels_oclsrc,
format("-D T=%s -D DECLARE_INPUT_MAT_N=%s -D DECLARE_OUTPUT_MAT_N=%s"
" -D PROCESS_ELEM_N=%s -D DECLARE_INDEX_N=%s%s",
ocl::memopTypeToStr(depth), declsrc.c_str(), decldst.c_str(),
declproc.c_str(), indexdecl.c_str(), declcn.c_str()));
if (k.empty())
return false;
int argindex = 0;
for (size_t i = 0; i < npairs; ++i)
argindex = k.set(argindex, ocl::KernelArg::ReadOnlyNoSize(srcargs[i]));
for (size_t i = 0; i < npairs; ++i)
argindex = k.set(argindex, ocl::KernelArg::WriteOnlyNoSize(dstargs[i]));
argindex = k.set(argindex, size.height);
argindex = k.set(argindex, size.width);
k.set(argindex, rowsPerWI);
size_t globalsize[2] = { (size_t)size.width, ((size_t)size.height + rowsPerWI - 1) / rowsPerWI };
return k.run(2, globalsize, NULL, false);
}
}
#endif
void cv::mixChannels(InputArrayOfArrays src, InputOutputArrayOfArrays dst,
const int* fromTo, size_t npairs)
{
CV_INSTRUMENT_REGION()
if (npairs == 0 || fromTo == NULL)
return;
CV_OCL_RUN(dst.isUMatVector(),
ocl_mixChannels(src, dst, fromTo, npairs))
bool src_is_mat = src.kind() != _InputArray::STD_VECTOR_MAT &&
src.kind() != _InputArray::STD_ARRAY_MAT &&
src.kind() != _InputArray::STD_VECTOR_VECTOR &&
src.kind() != _InputArray::STD_VECTOR_UMAT;
bool dst_is_mat = dst.kind() != _InputArray::STD_VECTOR_MAT &&
dst.kind() != _InputArray::STD_ARRAY_MAT &&
dst.kind() != _InputArray::STD_VECTOR_VECTOR &&
dst.kind() != _InputArray::STD_VECTOR_UMAT;
int i;
int nsrc = src_is_mat ? 1 : (int)src.total();
int ndst = dst_is_mat ? 1 : (int)dst.total();
CV_Assert(nsrc > 0 && ndst > 0);
cv::AutoBuffer<Mat> _buf(nsrc + ndst);
Mat* buf = _buf;
for( i = 0; i < nsrc; i++ )
buf[i] = src.getMat(src_is_mat ? -1 : i);
for( i = 0; i < ndst; i++ )
buf[nsrc + i] = dst.getMat(dst_is_mat ? -1 : i);
mixChannels(&buf[0], nsrc, &buf[nsrc], ndst, fromTo, npairs);
}
void cv::mixChannels(InputArrayOfArrays src, InputOutputArrayOfArrays dst,
const std::vector<int>& fromTo)
{
CV_INSTRUMENT_REGION()
if (fromTo.empty())
return;
CV_OCL_RUN(dst.isUMatVector(),
ocl_mixChannels(src, dst, &fromTo[0], fromTo.size()>>1))
bool src_is_mat = src.kind() != _InputArray::STD_VECTOR_MAT &&
src.kind() != _InputArray::STD_ARRAY_MAT &&
src.kind() != _InputArray::STD_VECTOR_VECTOR &&
src.kind() != _InputArray::STD_VECTOR_UMAT;
bool dst_is_mat = dst.kind() != _InputArray::STD_VECTOR_MAT &&
dst.kind() != _InputArray::STD_ARRAY_MAT &&
dst.kind() != _InputArray::STD_VECTOR_VECTOR &&
dst.kind() != _InputArray::STD_VECTOR_UMAT;
int i;
int nsrc = src_is_mat ? 1 : (int)src.total();
int ndst = dst_is_mat ? 1 : (int)dst.total();
CV_Assert(fromTo.size()%2 == 0 && nsrc > 0 && ndst > 0);
cv::AutoBuffer<Mat> _buf(nsrc + ndst);
Mat* buf = _buf;
for( i = 0; i < nsrc; i++ )
buf[i] = src.getMat(src_is_mat ? -1 : i);
for( i = 0; i < ndst; i++ )
buf[nsrc + i] = dst.getMat(dst_is_mat ? -1 : i);
mixChannels(&buf[0], nsrc, &buf[nsrc], ndst, &fromTo[0], fromTo.size()/2);
}
#ifdef HAVE_IPP
namespace cv
{
static bool ipp_extractChannel(const Mat &src, Mat &dst, int channel)
{
#ifdef HAVE_IPP_IW
CV_INSTRUMENT_REGION_IPP()
int srcChannels = src.channels();
int dstChannels = dst.channels();
if(src.dims != dst.dims)
return false;
if(src.dims <= 2)
{
IppiSize size = ippiSize(src.size());
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;
}
else
{
const Mat *arrays[] = {&dst, NULL};
uchar *ptrs[2] = {NULL};
NAryMatIterator it(arrays, ptrs);
IppiSize size = {(int)it.size, 1};
for( size_t i = 0; i < it.nplanes; i++, ++it )
{
if(CV_INSTRUMENT_FUN_IPP(llwiCopyChannel, ptrs[0], 0, srcChannels, channel, ptrs[1], 0, dstChannels, 0, size, (int)src.elemSize1()) < 0)
return false;
}
return true;
}
#else
CV_UNUSED(src); CV_UNUSED(dst); CV_UNUSED(channel);
return false;
#endif
}
static bool ipp_insertChannel(const Mat &src, Mat &dst, int channel)
{
#ifdef HAVE_IPP_IW
CV_INSTRUMENT_REGION_IPP()
int srcChannels = src.channels();
int dstChannels = dst.channels();
if(src.dims != dst.dims)
return false;
if(src.dims <= 2)
{
IppiSize size = ippiSize(src.size());
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;
}
else
{
const Mat *arrays[] = {&dst, NULL};
uchar *ptrs[2] = {NULL};
NAryMatIterator it(arrays, ptrs);
IppiSize size = {(int)it.size, 1};
for( size_t i = 0; i < it.nplanes; i++, ++it )
{
if(CV_INSTRUMENT_FUN_IPP(llwiCopyChannel, ptrs[0], 0, srcChannels, 0, ptrs[1], 0, dstChannels, channel, size, (int)src.elemSize1()) < 0)
return false;
}
return true;
}
#else
CV_UNUSED(src); CV_UNUSED(dst); CV_UNUSED(channel);
return false;
#endif
}
}
#endif
void cv::extractChannel(InputArray _src, OutputArray _dst, int coi)
{
CV_INSTRUMENT_REGION()
int type = _src.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
CV_Assert( 0 <= coi && coi < cn );
int ch[] = { coi, 0 };
#ifdef HAVE_OPENCL
if (ocl::isOpenCLActivated() && _src.dims() <= 2 && _dst.isUMat())
{
UMat src = _src.getUMat();
_dst.create(src.dims, &src.size[0], depth);
UMat dst = _dst.getUMat();
mixChannels(std::vector<UMat>(1, src), std::vector<UMat>(1, dst), ch, 1);
return;
}
#endif
Mat src = _src.getMat();
_dst.create(src.dims, &src.size[0], depth);
Mat dst = _dst.getMat();
CV_IPP_RUN_FAST(ipp_extractChannel(src, dst, coi))
mixChannels(&src, 1, &dst, 1, ch, 1);
}
void cv::insertChannel(InputArray _src, InputOutputArray _dst, int coi)
{
CV_INSTRUMENT_REGION()
int stype = _src.type(), sdepth = CV_MAT_DEPTH(stype), scn = CV_MAT_CN(stype);
int dtype = _dst.type(), ddepth = CV_MAT_DEPTH(dtype), dcn = CV_MAT_CN(dtype);
CV_Assert( _src.sameSize(_dst) && sdepth == ddepth );
CV_Assert( 0 <= coi && coi < dcn && scn == 1 );
int ch[] = { 0, coi };
#ifdef HAVE_OPENCL
if (ocl::isOpenCLActivated() && _src.dims() <= 2 && _dst.isUMat())
{
UMat src = _src.getUMat(), dst = _dst.getUMat();
mixChannels(std::vector<UMat>(1, src), std::vector<UMat>(1, dst), ch, 1);
return;
}
#endif
Mat src = _src.getMat(), dst = _dst.getMat();
CV_IPP_RUN_FAST(ipp_insertChannel(src, dst, coi))
mixChannels(&src, 1, &dst, 1, ch, 1);
}

@ -1,45 +1,7 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved.
// Copyright (C) 2014-2015, Itseez Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html
#include "precomp.hpp"
#include "convert.hpp"
@ -74,5 +36,5 @@ void cvtScale_s16s32f32Line_AVX2(const short* src, int* dst, float scale, float
}
}
}
} // cv::
/* End of file. */

File diff suppressed because it is too large Load Diff

@ -1,51 +1,11 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved.
// Copyright (C) 2014-2015, Itseez Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html
#include "precomp.hpp"
#include "precomp.hpp"
#include "convert.hpp"
namespace cv
{
namespace opt_FP16
@ -163,5 +123,5 @@ void cvtScaleHalf_SIMD16f32f( const short* src, size_t sstep, float* dst, size_t
#error "Unsupported build configuration"
#endif
}
}
/* End of file. */
} // cv::

@ -1,3 +1,12 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html
#ifndef SRC_CONVERT_HPP
#define SRC_CONVERT_HPP
#include "opencv2/core/types.hpp"
namespace
{
@ -185,4 +194,6 @@ namespace opt_SSE4_1
int cvtScale_SIMD_f64u16f32_SSE41(const double * src, ushort * dst, int width, float scale, float shift);
int Cvt_SIMD_f64u16_SSE41(const double * src, ushort * dst, int width);
}
}
}
#endif // SRC_CONVERT_HPP

@ -1,45 +1,7 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved.
// Copyright (C) 2014-2015, Itseez Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html
#include "precomp.hpp"
#include "convert.hpp"
@ -236,6 +198,6 @@ int Cvt_SIMD_f64u16_SSE41(const double * src, ushort * dst, int width)
}
}
}
} // cv::
/* End of file. */

@ -0,0 +1,134 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html
#include "precomp.hpp"
CV_IMPL void
cvSplit( const void* srcarr, void* dstarr0, void* dstarr1, void* dstarr2, void* dstarr3 )
{
void* dptrs[] = { dstarr0, dstarr1, dstarr2, dstarr3 };
cv::Mat src = cv::cvarrToMat(srcarr);
int i, j, nz = 0;
for( i = 0; i < 4; i++ )
nz += dptrs[i] != 0;
CV_Assert( nz > 0 );
std::vector<cv::Mat> dvec(nz);
std::vector<int> pairs(nz*2);
for( i = j = 0; i < 4; i++ )
{
if( dptrs[i] != 0 )
{
dvec[j] = cv::cvarrToMat(dptrs[i]);
CV_Assert( dvec[j].size() == src.size() );
CV_Assert( dvec[j].depth() == src.depth() );
CV_Assert( dvec[j].channels() == 1 );
CV_Assert( i < src.channels() );
pairs[j*2] = i;
pairs[j*2+1] = j;
j++;
}
}
if( nz == src.channels() )
cv::split( src, dvec );
else
{
cv::mixChannels( &src, 1, &dvec[0], nz, &pairs[0], nz );
}
}
CV_IMPL void
cvMerge( const void* srcarr0, const void* srcarr1, const void* srcarr2,
const void* srcarr3, void* dstarr )
{
const void* sptrs[] = { srcarr0, srcarr1, srcarr2, srcarr3 };
cv::Mat dst = cv::cvarrToMat(dstarr);
int i, j, nz = 0;
for( i = 0; i < 4; i++ )
nz += sptrs[i] != 0;
CV_Assert( nz > 0 );
std::vector<cv::Mat> svec(nz);
std::vector<int> pairs(nz*2);
for( i = j = 0; i < 4; i++ )
{
if( sptrs[i] != 0 )
{
svec[j] = cv::cvarrToMat(sptrs[i]);
CV_Assert( svec[j].size == dst.size &&
svec[j].depth() == dst.depth() &&
svec[j].channels() == 1 && i < dst.channels() );
pairs[j*2] = j;
pairs[j*2+1] = i;
j++;
}
}
if( nz == dst.channels() )
cv::merge( svec, dst );
else
{
cv::mixChannels( &svec[0], nz, &dst, 1, &pairs[0], nz );
}
}
CV_IMPL void
cvMixChannels( const CvArr** src, int src_count,
CvArr** dst, int dst_count,
const int* from_to, int pair_count )
{
cv::AutoBuffer<cv::Mat> buf(src_count + dst_count);
int i;
for( i = 0; i < src_count; i++ )
buf[i] = cv::cvarrToMat(src[i]);
for( i = 0; i < dst_count; i++ )
buf[i+src_count] = cv::cvarrToMat(dst[i]);
cv::mixChannels(&buf[0], src_count, &buf[src_count], dst_count, from_to, pair_count);
}
CV_IMPL void
cvConvertScaleAbs( const void* srcarr, void* dstarr,
double scale, double shift )
{
cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr);
CV_Assert( src.size == dst.size && dst.type() == CV_8UC(src.channels()));
cv::convertScaleAbs( src, dst, scale, shift );
}
CV_IMPL void
cvConvertScale( const void* srcarr, void* dstarr,
double scale, double shift )
{
cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr);
CV_Assert( src.size == dst.size && src.channels() == dst.channels() );
src.convertTo(dst, dst.type(), scale, shift);
}
CV_IMPL void cvLUT( const void* srcarr, void* dstarr, const void* lutarr )
{
cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr), lut = cv::cvarrToMat(lutarr);
CV_Assert( dst.size() == src.size() && dst.type() == CV_MAKETYPE(lut.depth(), src.channels()) );
cv::LUT( src, lut, dst );
}
CV_IMPL void cvNormalize( const CvArr* srcarr, CvArr* dstarr,
double a, double b, int norm_type, const CvArr* maskarr )
{
cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr), mask;
if( maskarr )
mask = cv::cvarrToMat(maskarr);
CV_Assert( dst.size() == src.size() && src.channels() == dst.channels() );
cv::normalize( src, dst, a, b, norm_type, dst.type(), mask );
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,417 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html
#include "precomp.hpp"
#include "opencl_kernels_core.hpp"
#include "convert.hpp"
#include "opencv2/core/openvx/ovx_defs.hpp"
/****************************************************************************************\
* LUT Transform *
\****************************************************************************************/
namespace cv
{
template<typename T> static void
LUT8u_( const uchar* src, const T* lut, T* dst, int len, int cn, int lutcn )
{
if( lutcn == 1 )
{
for( int i = 0; i < len*cn; i++ )
dst[i] = lut[src[i]];
}
else
{
for( int i = 0; i < len*cn; i += cn )
for( int k = 0; k < cn; k++ )
dst[i+k] = lut[src[i+k]*cn+k];
}
}
static void LUT8u_8u( const uchar* src, const uchar* lut, uchar* dst, int len, int cn, int lutcn )
{
LUT8u_( src, lut, dst, len, cn, lutcn );
}
static void LUT8u_8s( const uchar* src, const schar* lut, schar* dst, int len, int cn, int lutcn )
{
LUT8u_( src, lut, dst, len, cn, lutcn );
}
static void LUT8u_16u( const uchar* src, const ushort* lut, ushort* dst, int len, int cn, int lutcn )
{
LUT8u_( src, lut, dst, len, cn, lutcn );
}
static void LUT8u_16s( const uchar* src, const short* lut, short* dst, int len, int cn, int lutcn )
{
LUT8u_( src, lut, dst, len, cn, lutcn );
}
static void LUT8u_32s( const uchar* src, const int* lut, int* dst, int len, int cn, int lutcn )
{
LUT8u_( src, lut, dst, len, cn, lutcn );
}
static void LUT8u_32f( const uchar* src, const float* lut, float* dst, int len, int cn, int lutcn )
{
LUT8u_( src, lut, dst, len, cn, lutcn );
}
static void LUT8u_64f( const uchar* src, const double* lut, double* dst, int len, int cn, int lutcn )
{
LUT8u_( src, lut, dst, len, cn, lutcn );
}
typedef void (*LUTFunc)( const uchar* src, const uchar* lut, uchar* dst, int len, int cn, int lutcn );
static LUTFunc lutTab[] =
{
(LUTFunc)LUT8u_8u, (LUTFunc)LUT8u_8s, (LUTFunc)LUT8u_16u, (LUTFunc)LUT8u_16s,
(LUTFunc)LUT8u_32s, (LUTFunc)LUT8u_32f, (LUTFunc)LUT8u_64f, 0
};
#ifdef HAVE_OPENCL
static bool ocl_LUT(InputArray _src, InputArray _lut, OutputArray _dst)
{
int lcn = _lut.channels(), dcn = _src.channels(), ddepth = _lut.depth();
UMat src = _src.getUMat(), lut = _lut.getUMat();
_dst.create(src.size(), CV_MAKETYPE(ddepth, dcn));
UMat dst = _dst.getUMat();
int kercn = lcn == 1 ? std::min(4, ocl::predictOptimalVectorWidth(_src, _dst)) : dcn;
ocl::Kernel k("LUT", ocl::core::lut_oclsrc,
format("-D dcn=%d -D lcn=%d -D srcT=%s -D dstT=%s", kercn, lcn,
ocl::typeToStr(src.depth()), ocl::memopTypeToStr(ddepth)));
if (k.empty())
return false;
k.args(ocl::KernelArg::ReadOnlyNoSize(src), ocl::KernelArg::ReadOnlyNoSize(lut),
ocl::KernelArg::WriteOnly(dst, dcn, kercn));
size_t globalSize[2] = { (size_t)dst.cols * dcn / kercn, ((size_t)dst.rows + 3) / 4 };
return k.run(2, globalSize, NULL, false);
}
#endif
#ifdef HAVE_OPENVX
static bool openvx_LUT(Mat src, Mat dst, Mat _lut)
{
if (src.type() != CV_8UC1 || dst.type() != src.type() || _lut.type() != src.type() || !_lut.isContinuous())
return false;
try
{
ivx::Context ctx = ovx::getOpenVXContext();
ivx::Image
ia = ivx::Image::createFromHandle(ctx, VX_DF_IMAGE_U8,
ivx::Image::createAddressing(src.cols, src.rows, 1, (vx_int32)(src.step)), src.data),
ib = ivx::Image::createFromHandle(ctx, VX_DF_IMAGE_U8,
ivx::Image::createAddressing(dst.cols, dst.rows, 1, (vx_int32)(dst.step)), dst.data);
ivx::LUT lut = ivx::LUT::create(ctx);
lut.copyFrom(_lut);
ivx::IVX_CHECK_STATUS(vxuTableLookup(ctx, ia, lut, ib));
}
catch (ivx::RuntimeError & e)
{
VX_DbgThrow(e.what());
}
catch (ivx::WrapperError & e)
{
VX_DbgThrow(e.what());
}
return true;
}
#endif
#if defined(HAVE_IPP)
#if !IPP_DISABLE_PERF_LUT // there are no performance benefits (PR #2653)
namespace ipp {
class IppLUTParallelBody_LUTC1 : public ParallelLoopBody
{
public:
bool* ok;
const Mat& src_;
const Mat& lut_;
Mat& dst_;
int width;
size_t elemSize1;
IppLUTParallelBody_LUTC1(const Mat& src, const Mat& lut, Mat& dst, bool* _ok)
: ok(_ok), src_(src), lut_(lut), dst_(dst)
{
width = dst.cols * dst.channels();
elemSize1 = CV_ELEM_SIZE1(dst.depth());
CV_DbgAssert(elemSize1 == 1 || elemSize1 == 4);
*ok = true;
}
void operator()( const cv::Range& range ) const
{
if (!*ok)
return;
const int row0 = range.start;
const int row1 = range.end;
Mat src = src_.rowRange(row0, row1);
Mat dst = dst_.rowRange(row0, row1);
IppiSize sz = { width, dst.rows };
if (elemSize1 == 1)
{
if (CV_INSTRUMENT_FUN_IPP(ippiLUTPalette_8u_C1R, (const Ipp8u*)src.data, (int)src.step[0], dst.data, (int)dst.step[0], sz, lut_.data, 8) >= 0)
return;
}
else if (elemSize1 == 4)
{
if (CV_INSTRUMENT_FUN_IPP(ippiLUTPalette_8u32u_C1R, (const Ipp8u*)src.data, (int)src.step[0], (Ipp32u*)dst.data, (int)dst.step[0], sz, (Ipp32u*)lut_.data, 8) >= 0)
return;
}
*ok = false;
}
private:
IppLUTParallelBody_LUTC1(const IppLUTParallelBody_LUTC1&);
IppLUTParallelBody_LUTC1& operator=(const IppLUTParallelBody_LUTC1&);
};
class IppLUTParallelBody_LUTCN : public ParallelLoopBody
{
public:
bool *ok;
const Mat& src_;
const Mat& lut_;
Mat& dst_;
int lutcn;
uchar* lutBuffer;
uchar* lutTable[4];
IppLUTParallelBody_LUTCN(const Mat& src, const Mat& lut, Mat& dst, bool* _ok)
: ok(_ok), src_(src), lut_(lut), dst_(dst), lutBuffer(NULL)
{
lutcn = lut.channels();
IppiSize sz256 = {256, 1};
size_t elemSize1 = dst.elemSize1();
CV_DbgAssert(elemSize1 == 1);
lutBuffer = (uchar*)CV_IPP_MALLOC(256 * (int)elemSize1 * 4);
lutTable[0] = lutBuffer + 0;
lutTable[1] = lutBuffer + 1 * 256 * elemSize1;
lutTable[2] = lutBuffer + 2 * 256 * elemSize1;
lutTable[3] = lutBuffer + 3 * 256 * elemSize1;
CV_DbgAssert(lutcn == 3 || lutcn == 4);
if (lutcn == 3)
{
IppStatus status = CV_INSTRUMENT_FUN_IPP(ippiCopy_8u_C3P3R, lut.ptr(), (int)lut.step[0], lutTable, (int)lut.step[0], sz256);
if (status < 0)
return;
}
else if (lutcn == 4)
{
IppStatus status = CV_INSTRUMENT_FUN_IPP(ippiCopy_8u_C4P4R, lut.ptr(), (int)lut.step[0], lutTable, (int)lut.step[0], sz256);
if (status < 0)
return;
}
*ok = true;
}
~IppLUTParallelBody_LUTCN()
{
if (lutBuffer != NULL)
ippFree(lutBuffer);
lutBuffer = NULL;
lutTable[0] = NULL;
}
void operator()( const cv::Range& range ) const
{
if (!*ok)
return;
const int row0 = range.start;
const int row1 = range.end;
Mat src = src_.rowRange(row0, row1);
Mat dst = dst_.rowRange(row0, row1);
if (lutcn == 3)
{
if (CV_INSTRUMENT_FUN_IPP(ippiLUTPalette_8u_C3R, src.ptr(), (int)src.step[0], dst.ptr(), (int)dst.step[0], ippiSize(dst.size()), lutTable, 8) >= 0)
return;
}
else if (lutcn == 4)
{
if (CV_INSTRUMENT_FUN_IPP(ippiLUTPalette_8u_C4R, src.ptr(), (int)src.step[0], dst.ptr(), (int)dst.step[0], ippiSize(dst.size()), lutTable, 8) >= 0)
return;
}
*ok = false;
}
private:
IppLUTParallelBody_LUTCN(const IppLUTParallelBody_LUTCN&);
IppLUTParallelBody_LUTCN& operator=(const IppLUTParallelBody_LUTCN&);
};
} // namespace ipp
static bool ipp_lut(Mat &src, Mat &lut, Mat &dst)
{
CV_INSTRUMENT_REGION_IPP()
int lutcn = lut.channels();
if(src.dims > 2)
return false;
bool ok = false;
Ptr<ParallelLoopBody> body;
size_t elemSize1 = CV_ELEM_SIZE1(dst.depth());
if (lutcn == 1)
{
ParallelLoopBody* p = new ipp::IppLUTParallelBody_LUTC1(src, lut, dst, &ok);
body.reset(p);
}
else if ((lutcn == 3 || lutcn == 4) && elemSize1 == 1)
{
ParallelLoopBody* p = new ipp::IppLUTParallelBody_LUTCN(src, lut, dst, &ok);
body.reset(p);
}
if (body != NULL && ok)
{
Range all(0, dst.rows);
if (dst.total()>>18)
parallel_for_(all, *body, (double)std::max((size_t)1, dst.total()>>16));
else
(*body)(all);
if (ok)
return true;
}
return false;
}
#endif
#endif // IPP
class LUTParallelBody : public ParallelLoopBody
{
public:
bool* ok;
const Mat& src_;
const Mat& lut_;
Mat& dst_;
LUTFunc func;
LUTParallelBody(const Mat& src, const Mat& lut, Mat& dst, bool* _ok)
: ok(_ok), src_(src), lut_(lut), dst_(dst)
{
func = lutTab[lut.depth()];
*ok = (func != NULL);
}
void operator()( const cv::Range& range ) const
{
CV_DbgAssert(*ok);
const int row0 = range.start;
const int row1 = range.end;
Mat src = src_.rowRange(row0, row1);
Mat dst = dst_.rowRange(row0, row1);
int cn = src.channels();
int lutcn = lut_.channels();
const Mat* arrays[] = {&src, &dst, 0};
uchar* ptrs[2];
NAryMatIterator it(arrays, ptrs);
int len = (int)it.size;
for( size_t i = 0; i < it.nplanes; i++, ++it )
func(ptrs[0], lut_.ptr(), ptrs[1], len, cn, lutcn);
}
private:
LUTParallelBody(const LUTParallelBody&);
LUTParallelBody& operator=(const LUTParallelBody&);
};
} // cv::
void cv::LUT( InputArray _src, InputArray _lut, OutputArray _dst )
{
CV_INSTRUMENT_REGION()
int cn = _src.channels(), depth = _src.depth();
int lutcn = _lut.channels();
CV_Assert( (lutcn == cn || lutcn == 1) &&
_lut.total() == 256 && _lut.isContinuous() &&
(depth == CV_8U || depth == CV_8S) );
CV_OCL_RUN(_dst.isUMat() && _src.dims() <= 2,
ocl_LUT(_src, _lut, _dst))
Mat src = _src.getMat(), lut = _lut.getMat();
_dst.create(src.dims, src.size, CV_MAKETYPE(_lut.depth(), cn));
Mat dst = _dst.getMat();
CV_OVX_RUN(!ovx::skipSmallImages<VX_KERNEL_TABLE_LOOKUP>(src.cols, src.rows),
openvx_LUT(src, dst, lut))
#if !IPP_DISABLE_PERF_LUT
CV_IPP_RUN(_src.dims() <= 2, ipp_lut(src, lut, dst));
#endif
if (_src.dims() <= 2)
{
bool ok = false;
Ptr<ParallelLoopBody> body;
if (body == NULL || ok == false)
{
ok = false;
ParallelLoopBody* p = new LUTParallelBody(src, lut, dst, &ok);
body.reset(p);
}
if (body != NULL && ok)
{
Range all(0, dst.rows);
if (dst.total()>>18)
parallel_for_(all, *body, (double)std::max((size_t)1, dst.total()>>16));
else
(*body)(all);
if (ok)
return;
}
}
LUTFunc func = lutTab[lut.depth()];
CV_Assert( func != 0 );
const Mat* arrays[] = {&src, &dst, 0};
uchar* ptrs[2];
NAryMatIterator it(arrays, ptrs);
int len = (int)it.size;
for( size_t i = 0; i < it.nplanes; i++, ++it )
func(ptrs[0], lut.ptr(), ptrs[1], len, cn, lutcn);
}

@ -1,47 +1,10 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved.
// Copyright (C) 2014-2015, Itseez Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html
#include "precomp.hpp"
#include "opencl_kernels_core.hpp"
namespace cv { namespace hal {
@ -409,4 +372,232 @@ void merge64s(const int64** src, int64* dst, int len, int cn )
merge_(src, dst, len, cn);
}
}}
}} // cv::hal::
typedef void (*MergeFunc)(const uchar** src, uchar* dst, int len, int cn);
static MergeFunc getMergeFunc(int depth)
{
static MergeFunc mergeTab[] =
{
(MergeFunc)GET_OPTIMIZED(cv::hal::merge8u), (MergeFunc)GET_OPTIMIZED(cv::hal::merge8u), (MergeFunc)GET_OPTIMIZED(cv::hal::merge16u), (MergeFunc)GET_OPTIMIZED(cv::hal::merge16u),
(MergeFunc)GET_OPTIMIZED(cv::hal::merge32s), (MergeFunc)GET_OPTIMIZED(cv::hal::merge32s), (MergeFunc)GET_OPTIMIZED(cv::hal::merge64s), 0
};
return mergeTab[depth];
}
#ifdef HAVE_IPP
namespace cv {
static bool ipp_merge(const Mat* mv, Mat& dst, int channels)
{
#ifdef HAVE_IPP_IW
CV_INSTRUMENT_REGION_IPP()
if(channels != 3 && channels != 4)
return false;
if(mv[0].dims <= 2)
{
IppiSize size = ippiSize(mv[0].size());
const void *srcPtrs[4] = {NULL};
size_t srcStep = mv[0].step;
for(int i = 0; i < channels; i++)
{
srcPtrs[i] = mv[i].ptr();
if(srcStep != mv[i].step)
return false;
}
return CV_INSTRUMENT_FUN_IPP(llwiCopyMerge, srcPtrs, (int)srcStep, dst.ptr(), (int)dst.step, size, (int)mv[0].elemSize1(), channels, 0) >= 0;
}
else
{
const Mat *arrays[5] = {NULL};
uchar *ptrs[5] = {NULL};
arrays[0] = &dst;
for(int i = 1; i < channels; i++)
{
arrays[i] = &mv[i-1];
}
NAryMatIterator it(arrays, ptrs);
IppiSize size = { (int)it.size, 1 };
for( size_t i = 0; i < it.nplanes; i++, ++it )
{
if(CV_INSTRUMENT_FUN_IPP(llwiCopyMerge, (const void**)&ptrs[1], 0, ptrs[0], 0, size, (int)mv[0].elemSize1(), channels, 0) < 0)
return false;
}
return true;
}
#else
CV_UNUSED(dst); CV_UNUSED(mv); CV_UNUSED(channels);
return false;
#endif
}
}
#endif
void cv::merge(const Mat* mv, size_t n, OutputArray _dst)
{
CV_INSTRUMENT_REGION()
CV_Assert( mv && n > 0 );
int depth = mv[0].depth();
bool allch1 = true;
int k, cn = 0;
size_t i;
for( i = 0; i < n; i++ )
{
CV_Assert(mv[i].size == mv[0].size && mv[i].depth() == depth);
allch1 = allch1 && mv[i].channels() == 1;
cn += mv[i].channels();
}
CV_Assert( 0 < cn && cn <= CV_CN_MAX );
_dst.create(mv[0].dims, mv[0].size, CV_MAKETYPE(depth, cn));
Mat dst = _dst.getMat();
if( n == 1 )
{
mv[0].copyTo(dst);
return;
}
CV_IPP_RUN_FAST(ipp_merge(mv, dst, (int)n));
if( !allch1 )
{
AutoBuffer<int> pairs(cn*2);
int j, ni=0;
for( i = 0, j = 0; i < n; i++, j += ni )
{
ni = mv[i].channels();
for( k = 0; k < ni; k++ )
{
pairs[(j+k)*2] = j + k;
pairs[(j+k)*2+1] = j + k;
}
}
mixChannels( mv, n, &dst, 1, &pairs[0], cn );
return;
}
MergeFunc func = getMergeFunc(depth);
CV_Assert( func != 0 );
size_t esz = dst.elemSize(), esz1 = dst.elemSize1();
size_t blocksize0 = (int)((BLOCK_SIZE + esz-1)/esz);
AutoBuffer<uchar> _buf((cn+1)*(sizeof(Mat*) + sizeof(uchar*)) + 16);
const Mat** arrays = (const Mat**)(uchar*)_buf;
uchar** ptrs = (uchar**)alignPtr(arrays + cn + 1, 16);
arrays[0] = &dst;
for( k = 0; k < cn; k++ )
arrays[k+1] = &mv[k];
NAryMatIterator it(arrays, ptrs, cn+1);
size_t total = (int)it.size;
size_t blocksize = std::min((size_t)CV_SPLIT_MERGE_MAX_BLOCK_SIZE(cn), cn <= 4 ? total : std::min(total, blocksize0));
for( i = 0; i < it.nplanes; i++, ++it )
{
for( size_t j = 0; j < total; j += blocksize )
{
size_t bsz = std::min(total - j, blocksize);
func( (const uchar**)&ptrs[1], ptrs[0], (int)bsz, cn );
if( j + blocksize < total )
{
ptrs[0] += bsz*esz;
for( int t = 0; t < cn; t++ )
ptrs[t+1] += bsz*esz1;
}
}
}
}
#ifdef HAVE_OPENCL
namespace cv {
static bool ocl_merge( InputArrayOfArrays _mv, OutputArray _dst )
{
std::vector<UMat> src, ksrc;
_mv.getUMatVector(src);
CV_Assert(!src.empty());
int type = src[0].type(), depth = CV_MAT_DEPTH(type),
rowsPerWI = ocl::Device::getDefault().isIntel() ? 4 : 1;
Size size = src[0].size();
for (size_t i = 0, srcsize = src.size(); i < srcsize; ++i)
{
int itype = src[i].type(), icn = CV_MAT_CN(itype), idepth = CV_MAT_DEPTH(itype),
esz1 = CV_ELEM_SIZE1(idepth);
if (src[i].dims > 2)
return false;
CV_Assert(size == src[i].size() && depth == idepth);
for (int cn = 0; cn < icn; ++cn)
{
UMat tsrc = src[i];
tsrc.offset += cn * esz1;
ksrc.push_back(tsrc);
}
}
int dcn = (int)ksrc.size();
String srcargs, processelem, cndecl, indexdecl;
for (int i = 0; i < dcn; ++i)
{
srcargs += format("DECLARE_SRC_PARAM(%d)", i);
processelem += format("PROCESS_ELEM(%d)", i);
indexdecl += format("DECLARE_INDEX(%d)", i);
cndecl += format(" -D scn%d=%d", i, ksrc[i].channels());
}
ocl::Kernel k("merge", ocl::core::split_merge_oclsrc,
format("-D OP_MERGE -D cn=%d -D T=%s -D DECLARE_SRC_PARAMS_N=%s"
" -D DECLARE_INDEX_N=%s -D PROCESS_ELEMS_N=%s%s",
dcn, ocl::memopTypeToStr(depth), srcargs.c_str(),
indexdecl.c_str(), processelem.c_str(), cndecl.c_str()));
if (k.empty())
return false;
_dst.create(size, CV_MAKE_TYPE(depth, dcn));
UMat dst = _dst.getUMat();
int argidx = 0;
for (int i = 0; i < dcn; ++i)
argidx = k.set(argidx, ocl::KernelArg::ReadOnlyNoSize(ksrc[i]));
argidx = k.set(argidx, ocl::KernelArg::WriteOnly(dst));
k.set(argidx, rowsPerWI);
size_t globalsize[2] = { (size_t)dst.cols, ((size_t)dst.rows + rowsPerWI - 1) / rowsPerWI };
return k.run(2, globalsize, NULL, false);
}
}
#endif
void cv::merge(InputArrayOfArrays _mv, OutputArray _dst)
{
CV_INSTRUMENT_REGION()
CV_OCL_RUN(_mv.isUMatVector() && _dst.isUMat(),
ocl_merge(_mv, _dst))
std::vector<Mat> mv;
_mv.getMatVector(mv);
merge(!mv.empty() ? &mv[0] : 0, mv.size(), _dst);
}

@ -126,6 +126,10 @@ template<> inline uchar OpMin<uchar>::operator ()(uchar a, uchar b) const { retu
template<> inline uchar OpMax<uchar>::operator ()(uchar a, uchar b) const { return CV_MAX_8U(a, b); }
typedef void (*UnaryFunc)(const uchar* src1, size_t step1,
uchar* dst, size_t step, Size sz,
void*);
typedef void (*BinaryFunc)(const uchar* src1, size_t step1,
const uchar* src2, size_t step2,
uchar* dst, size_t step, Size sz,
@ -137,6 +141,7 @@ typedef void (*BinaryFuncC)(const uchar* src1, size_t step1,
void*);
BinaryFunc getConvertFunc(int sdepth, int ddepth);
BinaryFunc getConvertScaleFunc(int sdepth, int ddepth);
BinaryFunc getCopyMaskFunc(size_t esz);
/* default memory block for sparse array elements */
@ -198,6 +203,8 @@ struct NoVec
size_t operator()(const void*, const void*, void*, size_t) const { return 0; }
};
#define CV_SPLIT_MERGE_MAX_BLOCK_SIZE(cn) ((INT_MAX/4)/cn) // HAL implementation accepts 'int' len, so INT_MAX doesn't work here
enum { BLOCK_SIZE = 1024 };
#if defined HAVE_IPP && (IPP_VERSION_X100 >= 700)

@ -1,47 +1,10 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved.
// Copyright (C) 2014-2015, Itseez Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html
#include "precomp.hpp"
#include "opencl_kernels_core.hpp"
namespace cv { namespace hal {
@ -425,4 +388,202 @@ void split64s(const int64* src, int64** dst, int len, int cn )
split_(src, dst, len, cn);
}
}}
}} // cv::hal::
/****************************************************************************************\
* split & merge *
\****************************************************************************************/
typedef void (*SplitFunc)(const uchar* src, uchar** dst, int len, int cn);
static SplitFunc getSplitFunc(int depth)
{
static SplitFunc splitTab[] =
{
(SplitFunc)GET_OPTIMIZED(cv::hal::split8u), (SplitFunc)GET_OPTIMIZED(cv::hal::split8u), (SplitFunc)GET_OPTIMIZED(cv::hal::split16u), (SplitFunc)GET_OPTIMIZED(cv::hal::split16u),
(SplitFunc)GET_OPTIMIZED(cv::hal::split32s), (SplitFunc)GET_OPTIMIZED(cv::hal::split32s), (SplitFunc)GET_OPTIMIZED(cv::hal::split64s), 0
};
return splitTab[depth];
}
#ifdef HAVE_IPP
namespace cv {
static bool ipp_split(const Mat& src, Mat* mv, int channels)
{
#ifdef HAVE_IPP_IW
CV_INSTRUMENT_REGION_IPP()
if(channels != 3 && channels != 4)
return false;
if(src.dims <= 2)
{
IppiSize size = ippiSize(src.size());
void *dstPtrs[4] = {NULL};
size_t dstStep = mv[0].step;
for(int i = 0; i < channels; i++)
{
dstPtrs[i] = mv[i].ptr();
if(dstStep != mv[i].step)
return false;
}
return CV_INSTRUMENT_FUN_IPP(llwiCopySplit, src.ptr(), (int)src.step, dstPtrs, (int)dstStep, size, (int)src.elemSize1(), channels, 0) >= 0;
}
else
{
const Mat *arrays[5] = {NULL};
uchar *ptrs[5] = {NULL};
arrays[0] = &src;
for(int i = 1; i < channels; i++)
{
arrays[i] = &mv[i-1];
}
NAryMatIterator it(arrays, ptrs);
IppiSize size = { (int)it.size, 1 };
for( size_t i = 0; i < it.nplanes; i++, ++it )
{
if(CV_INSTRUMENT_FUN_IPP(llwiCopySplit, ptrs[0], 0, (void**)&ptrs[1], 0, size, (int)src.elemSize1(), channels, 0) < 0)
return false;
}
return true;
}
#else
CV_UNUSED(src); CV_UNUSED(mv); CV_UNUSED(channels);
return false;
#endif
}
}
#endif
void cv::split(const Mat& src, Mat* mv)
{
CV_INSTRUMENT_REGION()
int k, depth = src.depth(), cn = src.channels();
if( cn == 1 )
{
src.copyTo(mv[0]);
return;
}
for( k = 0; k < cn; k++ )
{
mv[k].create(src.dims, src.size, depth);
}
CV_IPP_RUN_FAST(ipp_split(src, mv, cn));
SplitFunc func = getSplitFunc(depth);
CV_Assert( func != 0 );
size_t esz = src.elemSize(), esz1 = src.elemSize1();
size_t blocksize0 = (BLOCK_SIZE + esz-1)/esz;
AutoBuffer<uchar> _buf((cn+1)*(sizeof(Mat*) + sizeof(uchar*)) + 16);
const Mat** arrays = (const Mat**)(uchar*)_buf;
uchar** ptrs = (uchar**)alignPtr(arrays + cn + 1, 16);
arrays[0] = &src;
for( k = 0; k < cn; k++ )
{
arrays[k+1] = &mv[k];
}
NAryMatIterator it(arrays, ptrs, cn+1);
size_t total = it.size;
size_t blocksize = std::min((size_t)CV_SPLIT_MERGE_MAX_BLOCK_SIZE(cn), cn <= 4 ? total : std::min(total, blocksize0));
for( size_t i = 0; i < it.nplanes; i++, ++it )
{
for( size_t j = 0; j < total; j += blocksize )
{
size_t bsz = std::min(total - j, blocksize);
func( ptrs[0], &ptrs[1], (int)bsz, cn );
if( j + blocksize < total )
{
ptrs[0] += bsz*esz;
for( k = 0; k < cn; k++ )
ptrs[k+1] += bsz*esz1;
}
}
}
}
#ifdef HAVE_OPENCL
namespace cv {
static bool ocl_split( InputArray _m, OutputArrayOfArrays _mv )
{
int type = _m.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type),
rowsPerWI = ocl::Device::getDefault().isIntel() ? 4 : 1;
String dstargs, processelem, indexdecl;
for (int i = 0; i < cn; ++i)
{
dstargs += format("DECLARE_DST_PARAM(%d)", i);
indexdecl += format("DECLARE_INDEX(%d)", i);
processelem += format("PROCESS_ELEM(%d)", i);
}
ocl::Kernel k("split", ocl::core::split_merge_oclsrc,
format("-D T=%s -D OP_SPLIT -D cn=%d -D DECLARE_DST_PARAMS=%s"
" -D PROCESS_ELEMS_N=%s -D DECLARE_INDEX_N=%s",
ocl::memopTypeToStr(depth), cn, dstargs.c_str(),
processelem.c_str(), indexdecl.c_str()));
if (k.empty())
return false;
Size size = _m.size();
_mv.create(cn, 1, depth);
for (int i = 0; i < cn; ++i)
_mv.create(size, depth, i);
std::vector<UMat> dst;
_mv.getUMatVector(dst);
int argidx = k.set(0, ocl::KernelArg::ReadOnly(_m.getUMat()));
for (int i = 0; i < cn; ++i)
argidx = k.set(argidx, ocl::KernelArg::WriteOnlyNoSize(dst[i]));
k.set(argidx, rowsPerWI);
size_t globalsize[2] = { (size_t)size.width, ((size_t)size.height + rowsPerWI - 1) / rowsPerWI };
return k.run(2, globalsize, NULL, false);
}
}
#endif
void cv::split(InputArray _m, OutputArrayOfArrays _mv)
{
CV_INSTRUMENT_REGION()
CV_OCL_RUN(_m.dims() <= 2 && _mv.isUMatVector(),
ocl_split(_m, _mv))
Mat m = _m.getMat();
if( m.empty() )
{
_mv.release();
return;
}
CV_Assert( !_mv.fixedType() || _mv.empty() || _mv.type() == m.depth() );
int depth = m.depth(), cn = m.channels();
_mv.create(cn, 1, depth);
for (int i = 0; i < cn; ++i)
_mv.create(m.dims, m.size.p, depth, i);
std::vector<Mat> dst;
_mv.getMatVector(dst);
split(m, &dst[0]);
}

Loading…
Cancel
Save