Merge pull request #26903 from asmorkalov:as/openvx_hal

Migrate remaning OpenVX integrations to OpenVX HAL (core) #26903

Tested with OpenVX 1.2 & 1.3 sample implementation.

Steps to build and test:
```
git clone git@github.com:KhronosGroup/OpenVX-sample-impl.git
cd OpenVX-sample-impl
python3 Build.py --os=Linux --conf=Release
cd ..
mkdir build
cmake -DWITH_OPENVX=ON -DOPENVX_ROOT=/mnt/Projects/Projects/OpenVX-sample-impl/install/Linux/x64/Release/ ../opencv
make -j8
```

### Pull Request Readiness Checklist

See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request

- [x] I agree to contribute to the project under Apache 2 License.
- [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV
- [ ] The PR is proposed to the proper branch
- [ ] There is a reference to the original bug report and related work
- [ ] There is accuracy test, performance test and test data in opencv_extra repository, if applicable
      Patch to opencv_extra has the same branch name.
- [ ] The feature is well documented and sample code can be built with the project CMake
This commit is contained in:
Alexander Smorkalov 2025-02-14 11:55:20 +03:00 committed by GitHub
parent e4b23cf96a
commit 58e557d059
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 211 additions and 199 deletions

View File

@ -191,7 +191,7 @@ int ovx_hal_mul(const T *a, size_t astep, const T *b, size_t bstep, T *c, size_t
#ifdef _WIN32
const float MAGIC_SCALE = 0x0.01010102p0;
#else
const float MAGIC_SCALE = 0x1.010102p-8;
const float MAGIC_SCALE = 0.003922; // 0x1.010102p-8;
#endif
try
{
@ -1145,3 +1145,192 @@ int ovx_hal_integral(int depth, int sdepth, int, const uchar * a, size_t astep,
return CV_HAL_ERROR_OK;
}
int ovx_hal_meanStdDev(const uchar* src_data, size_t src_step, int width, int height,
int src_type, double* mean_val, double* stddev_val, uchar* mask, size_t mask_step)
{
(void)mask_step;
if (src_type != CV_8UC1 || mask)
{
return CV_HAL_ERROR_NOT_IMPLEMENTED;
}
if (skipSmallImages<VX_KERNEL_MEAN_STDDEV>(width, height))
{
return CV_HAL_ERROR_NOT_IMPLEMENTED;
}
if (src_step == 0)
{
src_step = (int)width;
}
try
{
ivx::Context ctx = getOpenVXHALContext();
#ifndef VX_VERSION_1_1
if (ctx.vendorID() == VX_ID_KHRONOS)
return false; // Do not use OpenVX meanStdDev estimation for sample 1.0.1 implementation due to lack of accuracy
#endif
ivx::Image ia = ivx::Image::createFromHandle(ctx, VX_DF_IMAGE_U8,
ivx::Image::createAddressing(width, height, 1, (vx_int32)src_step), const_cast<uchar*>(src_data));
vx_float32 mean_temp, stddev_temp;
ivx::IVX_CHECK_STATUS(vxuMeanStdDev(ctx, ia, &mean_temp, &stddev_temp));
if (mean_val)
{
mean_val[0] = mean_temp;
}
if (stddev_val)
{
stddev_val[0] = stddev_temp;
}
}
catch (const ivx::RuntimeError & e)
{
PRINT_HALERR_MSG(runtime);
return CV_HAL_ERROR_UNKNOWN;
}
catch (const ivx::WrapperError & e)
{
PRINT_HALERR_MSG(wrapper);
return CV_HAL_ERROR_UNKNOWN;
}
return CV_HAL_ERROR_OK;
}
int ovx_hal_lut(const uchar *src_data, size_t src_step, size_t src_type,
const uchar* lut_data, size_t lut_channel_size, size_t lut_channels,
uchar *dst_data, size_t dst_step, int width, int height)
{
if (src_type != CV_8UC1 || lut_channels != 1 || lut_channel_size != 1)
{
return CV_HAL_ERROR_NOT_IMPLEMENTED;
}
if (skipSmallImages<VX_KERNEL_TABLE_LOOKUP>(width, height))
{
return CV_HAL_ERROR_NOT_IMPLEMENTED;
}
try
{
ivx::Context ctx = getOpenVXHALContext();
ivx::Image ia = ivx::Image::createFromHandle(ctx, VX_DF_IMAGE_U8,
ivx::Image::createAddressing(width, height, 1, (vx_int32)src_step),
const_cast<uchar*>(src_data));
ivx::Image ib = ivx::Image::createFromHandle(ctx, VX_DF_IMAGE_U8,
ivx::Image::createAddressing(width, height, 1, (vx_int32)dst_step),
dst_data);
ivx::LUT lut = ivx::LUT::create(ctx);
lut.copyFrom(lut_data);
ivx::IVX_CHECK_STATUS(vxuTableLookup(ctx, ia, lut, ib));
}
catch (const ivx::RuntimeError & e)
{
PRINT_HALERR_MSG(runtime);
return CV_HAL_ERROR_UNKNOWN;
}
catch (const ivx::WrapperError & e)
{
PRINT_HALERR_MSG(wrapper);
return CV_HAL_ERROR_UNKNOWN;
}
return CV_HAL_ERROR_OK;
}
template <> inline bool skipSmallImages<VX_KERNEL_MINMAXLOC>(int w, int h) { return w*h < 3840 * 2160; }
int ovx_hal_minMaxIdxMaskStep(const uchar* src_data, size_t src_step, int width, int height, int depth,
double* minVal, double* maxVal, int* minIdx, int* maxIdx, uchar* mask, size_t mask_step)
{
(void)mask_step;
if ((depth != CV_8U && depth != CV_16S) || mask )
{
return CV_HAL_ERROR_NOT_IMPLEMENTED;
}
if (skipSmallImages<VX_KERNEL_MINMAXLOC>(width, height))
{
return CV_HAL_ERROR_NOT_IMPLEMENTED;
}
if (src_step == 0)
{
src_step = (int)width;
}
try
{
ivx::Context ctx = getOpenVXHALContext();
ivx::Image ia = ivx::Image::createFromHandle(ctx, depth == CV_8U ? VX_DF_IMAGE_U8 : VX_DF_IMAGE_S16,
ivx::Image::createAddressing(width, height, depth == CV_8U ? 1 : 2, (vx_int32)src_step),
const_cast<uchar*>(src_data));
ivx::Scalar vxMinVal = ivx::Scalar::create(ctx, depth == CV_8U ? VX_TYPE_UINT8 : VX_TYPE_INT16, 0);
ivx::Scalar vxMaxVal = ivx::Scalar::create(ctx, depth == CV_8U ? VX_TYPE_UINT8 : VX_TYPE_INT16, 0);
ivx::Array vxMinInd, vxMaxInd;
ivx::Scalar vxMinCount, vxMaxCount;
if (minIdx)
{
vxMinInd = ivx::Array::create(ctx, VX_TYPE_COORDINATES2D, 1);
vxMinCount = ivx::Scalar::create(ctx, VX_TYPE_UINT32, 0);
}
if (maxIdx)
{
vxMaxInd = ivx::Array::create(ctx, VX_TYPE_COORDINATES2D, 1);
vxMaxCount = ivx::Scalar::create(ctx, VX_TYPE_UINT32, 0);
}
ivx::IVX_CHECK_STATUS(vxuMinMaxLoc(ctx, ia, vxMinVal, vxMaxVal, vxMinInd, vxMaxInd, vxMinCount, vxMaxCount));
if (minVal)
{
*minVal = depth == CV_8U ? vxMinVal.getValue<vx_uint8>() : vxMinVal.getValue<vx_int16>();
}
if (maxVal)
{
*maxVal = depth == CV_8U ? vxMaxVal.getValue<vx_uint8>() : vxMaxVal.getValue<vx_int16>();
}
if (minIdx)
{
if(vxMinCount.getValue<vx_uint32>()<1) throw ivx::RuntimeError(VX_ERROR_INVALID_VALUE, std::string(__func__) + "(): minimum value location not found");
vx_coordinates2d_t loc;
vxMinInd.copyRangeTo(0, 1, &loc);
minIdx[0] = loc.y;
minIdx[1] = loc.x;
}
if (maxIdx)
{
if (vxMaxCount.getValue<vx_uint32>()<1) throw ivx::RuntimeError(VX_ERROR_INVALID_VALUE, std::string(__func__) + "(): maximum value location not found");
vx_coordinates2d_t loc;
vxMaxInd.copyRangeTo(0, 1, &loc);
maxIdx[0] = loc.y;
maxIdx[1] = loc.x;
}
}
catch (const ivx::RuntimeError & e)
{
PRINT_HALERR_MSG(runtime);
return CV_HAL_ERROR_UNKNOWN;
}
catch (const ivx::WrapperError & e)
{
PRINT_HALERR_MSG(wrapper);
return CV_HAL_ERROR_UNKNOWN;
}
return CV_HAL_ERROR_OK;
}

View File

@ -54,6 +54,11 @@ int ovx_hal_cvtThreePlaneYUVtoBGR(const uchar * a, size_t astep, uchar * b, size
int ovx_hal_cvtBGRtoThreePlaneYUV(const uchar * a, size_t astep, uchar * b, size_t bstep, int w, int h, int acn, bool swapBlue, int uIdx);
int ovx_hal_cvtOnePlaneYUVtoBGR(const uchar * a, size_t astep, uchar * b, size_t bstep, int w, int h, int bcn, bool swapBlue, int uIdx, int ycn);
int ovx_hal_integral(int depth, int sdepth, int, const uchar * a, size_t astep, uchar * b, size_t bstep, uchar * c, size_t, uchar * d, size_t, int w, int h, int cn);
int ovx_hal_meanStdDev(const uchar* src_data, size_t src_step, int width, int height,
int src_type, double* mean_val, double* stddev_val, uchar* mask, size_t mask_step);
int ovx_hal_lut(const uchar *src_data, size_t src_step, size_t src_type, const uchar* lut_data, size_t lut_channel_size, size_t lut_channels, uchar *dst_data, size_t dst_step, int width, int height);
int ovx_hal_minMaxIdxMaskStep(const uchar* src_data, size_t src_step, int width, int height, int depth,
double* minVal, double* maxVal, int* minIdx, int* maxIdx, uchar* mask, size_t mask_step);
//==================================================================================================
// functions redefinition
@ -141,5 +146,11 @@ int ovx_hal_integral(int depth, int sdepth, int, const uchar * a, size_t astep,
#define cv_hal_cvtOnePlaneYUVtoBGR ovx_hal_cvtOnePlaneYUVtoBGR
#undef cv_hal_integral
#define cv_hal_integral ovx_hal_integral
#undef cv_hal_meanStdDev
#define cv_hal_meanStdDev ovx_hal_meanStdDev
#undef cv_hal_lut
#define cv_hal_lut ovx_hal_lut
#undef cv_hal_minMaxIdxMaskStep
#define cv_hal_minMaxIdxMaskStep ovx_hal_minMaxIdxMaskStep
#endif

View File

@ -22,7 +22,13 @@ Details: TBD
#include <VX/vx.h>
#include <VX/vxu.h>
#ifndef VX_VERSION_1_1
// For OpenVX 1.2 & 1.3
#if (VX_VERSION > VX_VERSION_1_1)
# include <VX/vx_compatibility.h>
#endif
#if (VX_VERSION == VX_VERSION_1_0)
// 1.1 to 1.0 backward compatibility defines
static const vx_enum VX_INTERPOLATION_BILINEAR = VX_INTERPOLATION_TYPE_BILINEAR;
@ -32,12 +38,6 @@ static const vx_enum VX_INTERPOLATION_NEAREST_NEIGHBOR = VX_INTERPOLATION_TYPE_N
static const vx_enum VX_BORDER_CONSTANT = VX_BORDER_MODE_CONSTANT;
static const vx_enum VX_BORDER_REPLICATE = VX_BORDER_MODE_REPLICATE;
#else
#ifdef IVX_RENAMED_REFS
static const vx_enum VX_REF_ATTRIBUTE_TYPE = VX_REFERENCE_TYPE;
#endif
#endif
#ifndef IVX_USE_CXX98
@ -218,7 +218,7 @@ template<> struct TypeToEnum<vx_int64> { static const vx_enum value = VX_TYPE
template<> struct TypeToEnum<vx_uint64> { static const vx_enum value = VX_TYPE_UINT64; };
template<> struct TypeToEnum<vx_float32> { static const vx_enum value = VX_TYPE_FLOAT32, imgType = VX_DF_IMAGE('F', '0', '3', '2'); };
template<> struct TypeToEnum<vx_float64> { static const vx_enum value = VX_TYPE_FLOAT64; };
template<> struct TypeToEnum<vx_bool> { static const vx_enum value = VX_TYPE_BOOL; };
//template<> struct TypeToEnum<vx_bool> { static const vx_enum value = VX_TYPE_BOOL; };
template<> struct TypeToEnum<vx_keypoint_t> {static const vx_enum value = VX_TYPE_KEYPOINT; };
// the commented types are aliases (of integral tyes) and have conflicts with the types above
//template<> struct TypeToEnum<vx_enum> { static const vx_enum val = VX_TYPE_ENUM; };

View File

@ -6,7 +6,6 @@
#include "precomp.hpp"
#include "opencl_kernels_core.hpp"
#include "convert.hpp"
#include "opencv2/core/openvx/ovx_defs.hpp"
/****************************************************************************************\
* LUT Transform *
@ -105,39 +104,6 @@ static bool ocl_LUT(InputArray _src, InputArray _lut, OutputArray _dst)
#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 (const ivx::RuntimeError& e)
{
VX_DbgThrow(e.what());
}
catch (const 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 {
@ -379,9 +345,6 @@ void cv::LUT( InputArray _src, InputArray _lut, OutputArray _dst )
_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))
CALL_HAL(LUT, cv_hal_lut, src.data, src.step, src.type(), lut.data,
lut.elemSize1(), lutcn, dst.data, dst.step, src.cols, src.rows);

View File

@ -5,7 +5,6 @@
#include "precomp.hpp"
#include "opencl_kernels_core.hpp"
#include "opencv2/core/openvx/ovx_defs.hpp"
#include "stat.hpp"
#ifndef OPENCV_IPP_MEAN
@ -328,70 +327,6 @@ static bool ocl_meanStdDev( InputArray _src, OutputArray _mean, OutputArray _sdv
}
#endif
#ifdef HAVE_OPENVX
static bool openvx_meanStdDev(Mat& src, OutputArray _mean, OutputArray _sdv, Mat& mask)
{
size_t total_size = src.total();
int rows = src.size[0], cols = rows ? (int)(total_size / rows) : 0;
if (src.type() != CV_8UC1|| !mask.empty() ||
(src.dims != 2 && !(src.isContinuous() && cols > 0 && (size_t)rows*cols == total_size))
)
return false;
try
{
ivx::Context ctx = ovx::getOpenVXContext();
#ifndef VX_VERSION_1_1
if (ctx.vendorID() == VX_ID_KHRONOS)
return false; // Do not use OpenVX meanStdDev estimation for sample 1.0.1 implementation due to lack of accuracy
#endif
ivx::Image
ia = ivx::Image::createFromHandle(ctx, VX_DF_IMAGE_U8,
ivx::Image::createAddressing(cols, rows, 1, (vx_int32)(src.step[0])), src.ptr());
vx_float32 mean_temp, stddev_temp;
ivx::IVX_CHECK_STATUS(vxuMeanStdDev(ctx, ia, &mean_temp, &stddev_temp));
if (_mean.needed())
{
if (!_mean.fixedSize())
_mean.create(1, 1, CV_64F, -1, true);
Mat mean = _mean.getMat();
CV_Assert(mean.type() == CV_64F && mean.isContinuous() &&
(mean.cols == 1 || mean.rows == 1) && mean.total() >= 1);
double *pmean = mean.ptr<double>();
pmean[0] = mean_temp;
for (int c = 1; c < (int)mean.total(); c++)
pmean[c] = 0;
}
if (_sdv.needed())
{
if (!_sdv.fixedSize())
_sdv.create(1, 1, CV_64F, -1, true);
Mat stddev = _sdv.getMat();
CV_Assert(stddev.type() == CV_64F && stddev.isContinuous() &&
(stddev.cols == 1 || stddev.rows == 1) && stddev.total() >= 1);
double *pstddev = stddev.ptr<double>();
pstddev[0] = stddev_temp;
for (int c = 1; c < (int)stddev.total(); c++)
pstddev[c] = 0;
}
}
catch (const ivx::RuntimeError & e)
{
VX_DbgThrow(e.what());
}
catch (const ivx::WrapperError & e)
{
VX_DbgThrow(e.what());
}
return true;
}
#endif
#ifdef HAVE_IPP
static bool ipp_meanStdDev(Mat& src, OutputArray _mean, OutputArray _sdv, Mat& mask)
{
@ -543,9 +478,6 @@ void meanStdDev(InputArray _src, OutputArray _mean, OutputArray _sdv, InputArray
CV_Assert(mask.empty() || src.size == mask.size);
CV_OVX_RUN(!ovx::skipSmallImages<VX_KERNEL_MEAN_STDDEV>(src.cols, src.rows),
openvx_meanStdDev(src, _mean, _sdv, mask))
CV_IPP_RUN(IPP_VERSION_X100 >= 700, ipp_meanStdDev(src, _mean, _sdv, mask));
int k, cn = src.channels(), depth = src.depth();

View File

@ -5,7 +5,6 @@
#include "precomp.hpp"
#include "opencl_kernels_core.hpp"
#include "opencv2/core/openvx/ovx_defs.hpp"
#include "stat.hpp"
#include "opencv2/core/detail/dispatch_helper.impl.hpp"
@ -1119,82 +1118,6 @@ bool ocl_minMaxIdx( InputArray _src, double* minVal, double* maxVal, int* minLoc
#endif
#ifdef HAVE_OPENVX
namespace ovx {
template <> inline bool skipSmallImages<VX_KERNEL_MINMAXLOC>(int w, int h) { return w*h < 3840 * 2160; }
}
static bool openvx_minMaxIdx(Mat &src, double* minVal, double* maxVal, int* minIdx, int* maxIdx, Mat &mask)
{
int stype = src.type();
size_t total_size = src.total();
int rows = src.size[0], cols = rows ? (int)(total_size / rows) : 0;
if ((stype != CV_8UC1 && stype != CV_16SC1) || !mask.empty() ||
(src.dims != 2 && !(src.isContinuous() && cols > 0 && (size_t)rows*cols == total_size))
)
return false;
try
{
ivx::Context ctx = ovx::getOpenVXContext();
ivx::Image
ia = ivx::Image::createFromHandle(ctx, stype == CV_8UC1 ? VX_DF_IMAGE_U8 : VX_DF_IMAGE_S16,
ivx::Image::createAddressing(cols, rows, stype == CV_8UC1 ? 1 : 2, (vx_int32)(src.step[0])), src.ptr());
ivx::Scalar vxMinVal = ivx::Scalar::create(ctx, stype == CV_8UC1 ? VX_TYPE_UINT8 : VX_TYPE_INT16, 0);
ivx::Scalar vxMaxVal = ivx::Scalar::create(ctx, stype == CV_8UC1 ? VX_TYPE_UINT8 : VX_TYPE_INT16, 0);
ivx::Array vxMinInd, vxMaxInd;
ivx::Scalar vxMinCount, vxMaxCount;
if (minIdx)
{
vxMinInd = ivx::Array::create(ctx, VX_TYPE_COORDINATES2D, 1);
vxMinCount = ivx::Scalar::create(ctx, VX_TYPE_UINT32, 0);
}
if (maxIdx)
{
vxMaxInd = ivx::Array::create(ctx, VX_TYPE_COORDINATES2D, 1);
vxMaxCount = ivx::Scalar::create(ctx, VX_TYPE_UINT32, 0);
}
ivx::IVX_CHECK_STATUS(vxuMinMaxLoc(ctx, ia, vxMinVal, vxMaxVal, vxMinInd, vxMaxInd, vxMinCount, vxMaxCount));
if (minVal)
{
*minVal = stype == CV_8UC1 ? vxMinVal.getValue<vx_uint8>() : vxMinVal.getValue<vx_int16>();
}
if (maxVal)
{
*maxVal = stype == CV_8UC1 ? vxMaxVal.getValue<vx_uint8>() : vxMaxVal.getValue<vx_int16>();
}
if (minIdx)
{
if(vxMinCount.getValue<vx_uint32>()<1) throw ivx::RuntimeError(VX_ERROR_INVALID_VALUE, std::string(__func__) + "(): minimum value location not found");
vx_coordinates2d_t loc;
vxMinInd.copyRangeTo(0, 1, &loc);
size_t minidx = loc.y * cols + loc.x + 1;
ofs2idx(src, minidx, minIdx);
}
if (maxIdx)
{
if (vxMaxCount.getValue<vx_uint32>()<1) throw ivx::RuntimeError(VX_ERROR_INVALID_VALUE, std::string(__func__) + "(): maximum value location not found");
vx_coordinates2d_t loc;
vxMaxInd.copyRangeTo(0, 1, &loc);
size_t maxidx = loc.y * cols + loc.x + 1;
ofs2idx(src, maxidx, maxIdx);
}
}
catch (const ivx::RuntimeError & e)
{
VX_DbgThrow(e.what());
}
catch (const ivx::WrapperError & e)
{
VX_DbgThrow(e.what());
}
return true;
}
#endif
#ifdef HAVE_IPP
static IppStatus ipp_minMaxIndex_wrap(const void* pSrc, int srcStep, IppiSize size, IppDataType dataType,
float* pMinVal, float* pMaxVal, IppiPoint* pMinIndex, IppiPoint* pMaxIndex, const Ipp8u*, int)
@ -1519,12 +1442,9 @@ void cv::minMaxIdx(InputArray _src, double* minVal,
CALL_HAL(minMaxIdx, cv_hal_minMaxIdx, src.data, src.step, src.cols*cn, src.rows,
src.depth(), minVal, maxVal, minIdx, maxIdx, mask.data);
}
else
{
CALL_HAL(minMaxIdxMaskStep, cv_hal_minMaxIdxMaskStep, src.data, src.step, src.cols*cn, src.rows,
src.depth(), minVal, maxVal, minIdx, maxIdx, mask.data, mask.step);
}
CALL_HAL(minMaxIdxMaskStep, cv_hal_minMaxIdxMaskStep, src.data, src.step, src.cols*cn, src.rows,
src.depth(), minVal, maxVal, minIdx, maxIdx, mask.data, mask.step);
}
else if (src.isContinuous() && mask.isContinuous())
{
@ -1547,9 +1467,6 @@ void cv::minMaxIdx(InputArray _src, double* minVal,
}
}
CV_OVX_RUN(!ovx::skipSmallImages<VX_KERNEL_MINMAXLOC>(src.cols, src.rows),
openvx_minMaxIdx(src, minVal, maxVal, minIdx, maxIdx, mask))
CV_IPP_RUN_FAST(ipp_minMaxIdx(src, minVal, maxVal, minIdx, maxIdx, mask))
MinMaxIdxFunc func = getMinmaxTab(depth);