mirror of https://github.com/opencv/opencv.git
Open Source Computer Vision Library
https://opencv.org/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
472 lines
15 KiB
472 lines
15 KiB
// 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.data(); |
|
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.data(); |
|
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.data(); |
|
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_LL |
|
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_LL |
|
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); |
|
}
|
|
|