mirror of https://github.com/opencv/opencv.git
Merge pull request #10797 from mshabunin:split-convert
commit
17233c687e
12 changed files with 4369 additions and 4531 deletions
@ -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); |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -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); |
||||
} |
Loading…
Reference in new issue