1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-21 19:33:03 +04:00

Merge branch 4.x

This commit is contained in:
Alexander Smorkalov
2026-07-14 09:13:24 +03:00
19 changed files with 922 additions and 522 deletions
@@ -81,7 +81,7 @@ pass in terms of square size).
So to find pattern in chess board, we can use the function, **cv.findChessboardCorners()**. We also
need to pass what kind of pattern we are looking for, like 8x8 grid, 5x5 grid etc. In this example, we
use 7x6 grid. (Normally a chess board has 8x8 squares and 7x7 internal corners). It returns the
use 6x7 grid. (Normally a chess board has 8x8 squares and 7x7 internal corners). It returns the
corner points and retval which will be True if pattern is obtained. These corners will be placed in
an order (from left-to-right, top-to-bottom)
@@ -107,9 +107,11 @@ import glob
# termination criteria
criteria = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER, 30, 0.001)
# prepare object points, like (0,0,0), (1,0,0), (2,0,0) ....,(6,5,0)
objp = np.zeros((6*7,3), np.float32)
objp[:,:2] = np.mgrid[0:7,0:6].T.reshape(-1,2)
# prepare object points, like (0,0,0), (1,0,0), (2,0,0) ....,(5,6,0)
cols = 6
rows = 7
objp = np.zeros((cols*rows,3), np.float32)
objp[:,:2] = np.mgrid[0:cols,0:rows].T.reshape(-1,2)
# Arrays to store object points and image points from all the images.
objpoints = [] # 3d point in real world space
@@ -122,7 +124,7 @@ for fname in images:
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
# Find the chess board corners
ret, corners = cv.findChessboardCorners(gray, (7,6), None)
ret, corners = cv.findChessboardCorners(gray, (cols, rows), None)
# If found, add object points, image points (after refining them)
if ret == True:
@@ -132,7 +134,7 @@ for fname in images:
imgpoints.append(corners2)
# Draw and display the corners
cv.drawChessboardCorners(img, (7,6), corners2, ret)
cv.drawChessboardCorners(img, (cols, rows), corners2, ret)
cv.imshow('img', img)
cv.waitKey(500)
@@ -50,12 +50,14 @@ our X axis is drawn from (0,0,0) to (3,0,0), so for Y axis. For Z axis, it is dr
(0,0,-3). Negative denotes it is drawn towards the camera.
@code{.py}
criteria = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER, 30, 0.001)
objp = np.zeros((6*7,3), np.float32)
objp[:,:2] = np.mgrid[0:7,0:6].T.reshape(-1,2)
cols = 6
rows = 7
objp = np.zeros((cols*rows,3), np.float32)
objp[:,:2] = np.mgrid[0:cols,0:rows].T.reshape(-1,2)
axis = np.float32([[3,0,0], [0,3,0], [0,0,-3]]).reshape(-1,3)
@endcode
Now, as usual, we load each image. Search for 7x6 grid. If found, we refine it with subcorner
Now, as usual, we load each image. Search for 6x7 grid. If found, we refine it with subcorner
pixels. Then to calculate the rotation and translation, we use the function,
**cv.solvePnPRansac()**. Once we those transformation matrices, we use them to project our **axis
points** to the image plane. In simple words, we find the points on image plane corresponding to
@@ -65,7 +67,7 @@ to each of these points using our generateImage() function. Done !!!
for fname in glob.glob('left*.jpg'):
img = cv.imread(fname)
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
ret, corners = cv.findChessboardCorners(gray, (7,6),None)
ret, corners = cv.findChessboardCorners(gray, (cols, rows), None)
if ret == True:
corners2 = cv.cornerSubPix(gray,corners,(11,11),(-1,-1),criteria)
+5
View File
@@ -23,6 +23,10 @@ add_library(ipphal STATIC
"${CMAKE_CURRENT_SOURCE_DIR}/src/sum_ipp.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/color_ipp.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/filter_ipp.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/matchtemplate_ipp.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/canny_ipp.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/threshold_ipp.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/distancetransform_ipp.cpp"
)
#TODO: HAVE_IPP_ICV and HAVE_IPP_IW added as private macro till OpenCV itself is
@@ -49,6 +53,7 @@ target_include_directories(ipphal PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/src"
${CMAKE_SOURCE_DIR}/modules/core/include
${CMAKE_SOURCE_DIR}/modules/imgproc/include
${CMAKE_SOURCE_DIR}/modules/geometry/include
${IPP_INCLUDE_DIRS}
)
+44 -8
View File
@@ -52,13 +52,6 @@ int ipp_hal_warpPerspective(int src_type, const uchar *src_data, size_t src_step
#endif // IPP_VERSION_X100 >= 202600
int ipp_hal_remap32f(int src_type, const uchar *src_data, size_t src_step, int src_width, int src_height,
uchar *dst_data, size_t dst_step, int dst_width, int dst_height,
float* mapx, size_t mapx_step, float* mapy, size_t mapy_step,
int interpolation, int border_type, const double border_value[4]);
#undef cv_hal_remap32f
#define cv_hal_remap32f ipp_hal_remap32f
#if defined(HAVE_IPP_IW)
int ipp_hal_resize(int src_type, const uchar *src_data, size_t src_step, int src_width, int src_height,
uchar *dst_data, size_t dst_step, int dst_width, int dst_height,
@@ -77,6 +70,13 @@ int ipp_hal_boxFilter(const uchar* src_data, size_t src_step, uchar* dst_data, s
#define cv_hal_boxFilter ipp_hal_boxFilter
#endif // defined(HAVE_IPP_IW) && !DISABLE_IPP_BOX_FILTER
int ipp_hal_remap32f(int src_type, const uchar *src_data, size_t src_step, int src_width, int src_height,
uchar *dst_data, size_t dst_step, int dst_width, int dst_height,
float* mapx, size_t mapx_step, float* mapy, size_t mapy_step,
int interpolation, int border_type, const double border_value[4]);
#undef cv_hal_remap32f
#define cv_hal_remap32f ipp_hal_remap32f
#if defined(HAVE_IPP_IW) && !DISABLE_IPP_FILTER2D
int ipp_hal_filter2D(const uchar * src_data, size_t src_step, int src_type,
uchar * dst_data, size_t dst_step, int dst_type,
@@ -174,6 +174,42 @@ int ipp_hal_cvtLabtoBGR(const uchar * src_data, size_t src_step, uchar * dst_dat
#define cv_hal_cvtLabtoBGR ipp_hal_cvtLabtoBGR
#endif // !IPP_DISABLE_LAB_RGB
#endif //IPP_VERSION_X100 >= 700
int ipp_hal_cvtRGBAtoMultipliedRGBA(const uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int width, int height);
#undef cv_hal_cvtRGBAtoMultipliedRGBA
#define cv_hal_cvtRGBAtoMultipliedRGBA ipp_hal_cvtRGBAtoMultipliedRGBA
int ipp_hal_matchTemplate(const uchar* src_data, size_t src_step, int src_width, int src_height,
const uchar* templ_data, size_t templ_step, int templ_width, int templ_height,
float* result_data, size_t result_step, int depth, int cn, int method);
#undef cv_hal_matchTemplate
#define cv_hal_matchTemplate ipp_hal_matchTemplate
int ipp_hal_threshold(const uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step,
int width, int height, int depth, int cn, double thresh, double maxValue, int thresholdType);
#undef cv_hal_threshold
#define cv_hal_threshold ipp_hal_threshold
int ipp_hal_distanceTransform(const uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step,
int width, int height, int dst_type, int dist_type, int mask_size);
#undef cv_hal_distanceTransform
#define cv_hal_distanceTransform ipp_hal_distanceTransform
#endif // IPP_VERSION_X100 >= 700
#define IPP_DISABLE_PERF_CANNY_MT 1 // cv::Canny OpenCV MT performance is better
#if defined(HAVE_IPP_IW)
int ipp_hal_canny(const uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step,
int width, int height, int cn,
double lowThreshold, double highThreshold, int ksize, bool L2gradient);
#undef cv_hal_canny
#define cv_hal_canny ipp_hal_canny
int ipp_hal_canny_deriv(const short* dx_data, size_t dx_step, const short* dy_data, size_t dy_step,
uchar* dst_data, size_t dst_step, int width, int height, int cn,
double lowThreshold, double highThreshold, bool L2gradient);
#undef cv_hal_canny_deriv
#define cv_hal_canny_deriv ipp_hal_canny_deriv
#endif
#endif //__IPP_HAL_IMGPROC_HPP__
+95
View File
@@ -0,0 +1,95 @@
// 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
// Copyright (C) 2026, BigVision LLC, all rights reserved.
// Third party copyrights are property of their respective owners.
#include "ipp_hal_imgproc.hpp"
#ifdef HAVE_IPP_IW
#include <opencv2/core.hpp>
#include "precomp_ipp.hpp"
int ipp_hal_canny(const uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step,
int width, int height, int cn,
double lowThreshold, double highThreshold, int ksize, bool L2gradient)
{
CV_HAL_CHECK_USE_IPP();
#if IPP_DISABLE_PERF_CANNY_MT
if(cv::getNumThreads() > 1)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
#endif
if(width <= 3 || height <= 3)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
if(cn != 1)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
IppiMaskSize kernel;
if(ksize == 3)
kernel = ippMskSize3x3;
else if(ksize == 5)
kernel = ippMskSize5x5;
else
return CV_HAL_ERROR_NOT_IMPLEMENTED;
IppNormType norm = L2gradient ? ippNormL2 : ippNormL1;
try
{
::ipp::IwiImage iwSrc, iwDst;
iwSrc.Init(IwiSize{width, height}, ipp8u, cn, ::ipp::IwiBorderSize(), (void*)src_data, IwSize(src_step));
iwDst.Init(IwiSize{width, height}, ipp8u, cn, ::ipp::IwiBorderSize(), dst_data, IwSize(dst_step));
CV_INSTRUMENT_FUN_IPP(::ipp::iwiFilterCanny, iwSrc, iwDst, (float)lowThreshold, (float)highThreshold,
::ipp::IwiFilterCannyParams(ippFilterSobel, kernel, norm), ippBorderRepl);
}
catch (const ::ipp::IwException &)
{
return CV_HAL_ERROR_NOT_IMPLEMENTED;
}
return CV_HAL_ERROR_OK;
}
int ipp_hal_canny_deriv(const short* dx_data, size_t dx_step, const short* dy_data, size_t dy_step,
uchar* dst_data, size_t dst_step, int width, int height, int cn,
double lowThreshold, double highThreshold, bool L2gradient)
{
CV_HAL_CHECK_USE_IPP();
#if IPP_DISABLE_PERF_CANNY_MT
if(cv::getNumThreads() > 1)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
#endif
if(width <= 3 || height <= 3)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
if(cn != 1)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
IppNormType norm = L2gradient ? ippNormL2 : ippNormL1;
try
{
::ipp::IwiImage iwSrcDx, iwSrcDy, iwDst;
iwSrcDx.Init(IwiSize{width, height}, ipp16s, cn, ::ipp::IwiBorderSize(), (void*)dx_data, IwSize(dx_step));
iwSrcDy.Init(IwiSize{width, height}, ipp16s, cn, ::ipp::IwiBorderSize(), (void*)dy_data, IwSize(dy_step));
iwDst.Init(IwiSize{width, height}, ipp8u, cn, ::ipp::IwiBorderSize(), dst_data, IwSize(dst_step));
CV_INSTRUMENT_FUN_IPP(::ipp::iwiFilterCannyDeriv, iwSrcDx, iwSrcDy, iwDst, (float)lowThreshold, (float)highThreshold,
::ipp::IwiFilterCannyDerivParams(norm));
}
catch (const ::ipp::IwException &)
{
return CV_HAL_ERROR_NOT_IMPLEMENTED;
}
return CV_HAL_ERROR_OK;
}
#endif
+149
View File
@@ -0,0 +1,149 @@
// 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
// Copyright (C) 2026, BigVision LLC, all rights reserved.
// Third party copyrights are property of their respective owners.
#include "ipp_hal_imgproc.hpp"
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/geometry.hpp>
#include <climits>
#include <cmath>
#if IPP_VERSION_X100 >= 700
// Mirrors CV_IPP_MALLOC from modules/core/include/opencv2/core/private.hpp: ippicv (IPP >= 2017)
// exposes only the 64-bit ippMalloc_L.
#if IPP_VERSION_X100 >= 201700
#define IPP_HAL_MALLOC(SIZE) ippMalloc_L(SIZE)
#else
#define IPP_HAL_MALLOC(SIZE) ippMalloc((int)(SIZE))
#endif
#ifndef IPP_DISABLE_PERF_TRUE_DIST_MT
#define IPP_DISABLE_PERF_TRUE_DIST_MT 1
#endif
// Fixed distance-transform mask weights, mirroring getDistanceTransformMask() in
// modules/imgproc/src/distransform.cpp. maskType == distTypeIndex + mask_size*10.
static bool ippGetDistanceTransformMask(int dist_type, int mask_size, float *metrics)
{
int maskType = (dist_type == cv::DIST_C ? 0 : dist_type == cv::DIST_L1 ? 1 : 2) + mask_size * 10;
switch (maskType)
{
case 30: metrics[0] = 1.0f; metrics[1] = 1.0f; break;
case 31: metrics[0] = 1.0f; metrics[1] = 2.0f; break;
case 32: metrics[0] = 0.955f; metrics[1] = 1.3693f; break;
case 50: metrics[0] = 1.0f; metrics[1] = 1.0f; metrics[2] = 2.0f; break;
case 51: metrics[0] = 1.0f; metrics[1] = 2.0f; metrics[2] = 3.0f; break;
case 52: metrics[0] = 1.0f; metrics[1] = 1.4f; metrics[2] = 2.1969f; break;
default:
return false;
}
return true;
}
int ipp_hal_distanceTransform(const uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step,
int width, int height, int dst_type, int dist_type, int mask_size)
{
CV_HAL_CHECK_USE_IPP();
IppiSize roi = { width, height };
// DIST_L1 with 8-bit output: fixed L1 / 3x3 metrics.
if (dst_type == CV_8U)
{
Ipp32s pMetrics[2] = { 1, 2 }; // L1, 3x3 mask
if (CV_INSTRUMENT_FUN_IPP(ippiDistanceTransform_3x3_8u_C1R, src_data, (int)src_step,
dst_data, (int)dst_step, roi, pMetrics) >= 0)
{
return CV_HAL_ERROR_OK;
}
return CV_HAL_ERROR_NOT_IMPLEMENTED;
}
// All remaining paths produce a 32-bit float distance map.
if (dst_type != CV_32F)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
if (mask_size == cv::DIST_MASK_PRECISE)
{
// 4097 can't square into a float.
#if IPP_DISABLE_PERF_TRUE_DIST_MT
if (!((cv::getNumThreads() <= 1 || ((size_t)width * height < (size_t)(1 << 14))) &&
height < 4097 && width < 4097))
{
return CV_HAL_ERROR_NOT_IMPLEMENTED;
}
#endif
int bufSize = 0;
if (ippiTrueDistanceTransformGetBufferSize_8u32f_C1R(roi, &bufSize) < 0)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
Ipp8u *pBuffer = (Ipp8u *)IPP_HAL_MALLOC(bufSize);
if (!pBuffer)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
IppStatus status = CV_INSTRUMENT_FUN_IPP(ippiTrueDistanceTransform_8u32f_C1R, src_data, (int)src_step,
(Ipp32f *)dst_data, (int)dst_step, roi, pBuffer);
ippFree(pBuffer);
if (status < 0)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
// https://github.com/opencv/opencv/issues/24082
// There is probably a rounding issue that leads to non-deterministic behavior
// between runs on positions closer to zeros by x-axis in straight direction.
// As a workaround, we detect the distances that expected to be exact
// number of pixels and round manually.
static const float correctionDiff = 1.0f / (1 << 11);
for (int i = 0; i < height; ++i)
{
float* row = (float*)(dst_data + (size_t)i * dst_step);
for (int j = 0; j < width; ++j)
{
float rounded = static_cast<float>(cvRound(row[j]));
if (std::fabs(row[j] - rounded) <= correctionDiff)
row[j] = rounded;
}
}
return CV_HAL_ERROR_OK;
}
// DIST_MASK_3 / DIST_MASK_5 chamfer distances.
if (mask_size != cv::DIST_MASK_3 && mask_size != cv::DIST_MASK_5)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
// IPP uses 32-bit signed intermediates; bail out when the image is too large.
bool has_int_overflow = (int64)width * height >= INT_MAX;
if (has_int_overflow)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
float metrics[5] = {0};
if (!ippGetDistanceTransformMask(dist_type, mask_size, metrics))
return CV_HAL_ERROR_NOT_IMPLEMENTED;
if (mask_size == cv::DIST_MASK_3)
{
if (CV_INSTRUMENT_FUN_IPP(ippiDistanceTransform_3x3_8u32f_C1R, src_data, (int)src_step,
(Ipp32f *)dst_data, (int)dst_step, roi, metrics) >= 0)
{
return CV_HAL_ERROR_OK;
}
}
else // DIST_MASK_5
{
if (CV_INSTRUMENT_FUN_IPP(ippiDistanceTransform_5x5_8u32f_C1R, src_data, (int)src_step,
(Ipp32f *)dst_data, (int)dst_step, roi, metrics) >= 0)
{
return CV_HAL_ERROR_OK;
}
}
return CV_HAL_ERROR_NOT_IMPLEMENTED;
}
#endif // IPP_VERSION_X100 >= 700
+144
View File
@@ -0,0 +1,144 @@
// 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
// Copyright (C) 2026, BigVision LLC, all rights reserved.
// Third party copyrights are property of their respective owners.
#include "ipp_hal_imgproc.hpp"
#include <opencv2/core.hpp>
#include "precomp_ipp.hpp"
#if IPP_VERSION_X100 >= 700
using namespace cv;
#if IPP_VERSION_X100 >= 201700
#define IPP_HAL_MALLOC(SIZE) ippMalloc_L(SIZE)
#else
#define IPP_HAL_MALLOC(SIZE) ippMalloc((int)(SIZE))
#endif
typedef IppStatus (CV_STDCALL * ippimatchTemplate)(const void*, int, IppiSize, const void*, int, IppiSize, Ipp32f* , int , IppEnum , Ipp8u*);
static bool ipp_crossCorr(const Mat& src, const Mat& tpl, Mat& dst, bool normed)
{
IppStatus status;
IppiSize srcRoiSize = {src.cols,src.rows};
IppiSize tplRoiSize = {tpl.cols,tpl.rows};
int bufSize=0;
int depth = src.depth();
ippimatchTemplate ippiCrossCorrNorm =
depth==CV_8U ? (ippimatchTemplate)ippiCrossCorrNorm_8u32f_C1R:
depth==CV_32F? (ippimatchTemplate)ippiCrossCorrNorm_32f_C1R: 0;
if (ippiCrossCorrNorm==0)
return false;
IppEnum funCfg = (IppEnum)(+ippAlgAuto | ippiROIValid);
if(normed)
funCfg |= ippiNorm;
else
funCfg |= ippiNormNone;
status = ippiCrossCorrNormGetBufferSize(srcRoiSize, tplRoiSize, funCfg, &bufSize);
if ( status < 0 )
return false;
Ipp8u* buffer = bufSize > 0 ? (Ipp8u*)IPP_HAL_MALLOC(bufSize) : 0;
if (bufSize > 0 && buffer == 0)
return false;
status = CV_INSTRUMENT_FUN_IPP(ippiCrossCorrNorm, src.ptr(), (int)src.step, srcRoiSize, tpl.ptr(), (int)tpl.step, tplRoiSize, dst.ptr<Ipp32f>(), (int)dst.step, funCfg, buffer);
if (buffer)
ippFree(buffer);
return status >= 0;
}
static bool ipp_sqrDistance(const Mat& src, const Mat& tpl, Mat& dst)
{
IppStatus status;
IppiSize srcRoiSize = {src.cols,src.rows};
IppiSize tplRoiSize = {tpl.cols,tpl.rows};
int bufSize=0;
int depth = src.depth();
ippimatchTemplate ippiSqrDistanceNorm =
depth==CV_8U ? (ippimatchTemplate)ippiSqrDistanceNorm_8u32f_C1R:
depth==CV_32F? (ippimatchTemplate)ippiSqrDistanceNorm_32f_C1R: 0;
if (ippiSqrDistanceNorm==0)
return false;
IppEnum funCfg = (IppEnum)(+ippAlgAuto | ippiROIValid | ippiNormNone);
status = ippiSqrDistanceNormGetBufferSize(srcRoiSize, tplRoiSize, funCfg, &bufSize);
if ( status < 0 )
return false;
Ipp8u* buffer = bufSize > 0 ? (Ipp8u*)IPP_HAL_MALLOC(bufSize) : 0;
if (bufSize > 0 && buffer == 0)
return false;
status = CV_INSTRUMENT_FUN_IPP(ippiSqrDistanceNorm, src.ptr(), (int)src.step, srcRoiSize, tpl.ptr(), (int)tpl.step, tplRoiSize, dst.ptr<Ipp32f>(), (int)dst.step, funCfg, buffer);
if (buffer)
ippFree(buffer);
dst = cv::max(dst, 0); // handle edge case from rounding in variance computation which can result in negative values
return status >= 0;
}
int ipp_hal_matchTemplate(const uchar* src_data, size_t src_step, int src_width, int src_height,
const uchar* templ_data, size_t templ_step, int templ_width, int templ_height,
float* result_data, size_t result_step, int depth, int cn, int method)
{
CV_HAL_CHECK_USE_IPP();
if(cn != 1)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
if(depth != CV_8U && depth != CV_32F)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
Mat img(src_height, src_width, CV_MAKETYPE(depth, cn), (void*)src_data, src_step);
Mat templ(templ_height, templ_width, CV_MAKETYPE(depth, cn), (void*)templ_data, templ_step);
Mat result(src_height - templ_height + 1, src_width - templ_width + 1, CV_32FC1, (void*)result_data, result_step);
// These functions are not efficient if template size is comparable with image size
if(templ.size().area()*4 > img.size().area())
return CV_HAL_ERROR_NOT_IMPLEMENTED;
// CV_8U SQDIFF/SQDIFF_NORMED suffer from float32 catastrophic cancellation
// in IPP's internal accumulators; fall through to the double-precision path instead.
if(depth == CV_8U && (method == cv::TM_SQDIFF || method == cv::TM_SQDIFF_NORMED))
return CV_HAL_ERROR_NOT_IMPLEMENTED;
if(method == cv::TM_SQDIFF)
{
if(ipp_sqrDistance(img, templ, result))
return CV_HAL_ERROR_OK;
}
else if(method == cv::TM_CCORR_NORMED)
{
if(ipp_crossCorr(img, templ, result, true))
return CV_HAL_ERROR_OK;
}
else if(method == cv::TM_SQDIFF_NORMED || method == cv::TM_CCORR ||
method == cv::TM_CCOEFF || method == cv::TM_CCOEFF_NORMED)
{
// Raw cross-correlation; caller finishes SQDIFF_NORMED/CCOEFF/CCOEFF_NORMED via
// common_matchTemplate (TM_CCORR is already final).
if(ipp_crossCorr(img, templ, result, false))
return CV_HAL_ERROR_OK;
}
return CV_HAL_ERROR_NOT_IMPLEMENTED;
}
#endif // IPP_VERSION_X100 >= 700
+128
View File
@@ -0,0 +1,128 @@
// 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
// Copyright (C) 2026, BigVision LLC, all rights reserved.
// Third party copyrights are property of their respective owners.
#include "ipp_hal_imgproc.hpp"
#include <opencv2/core.hpp>
#include "precomp_ipp.hpp"
#include <cmath>
#include <limits>
#if IPP_VERSION_X100 >= 700
int ipp_hal_threshold(const uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step,
int width, int height, int depth, int cn, double thresh, double maxValue,
int thresholdType)
{
CV_HAL_CHECK_USE_IPP();
CV_UNUSED(maxValue);
// IPP only implements these three types and depths; everything else falls back to OpenCV.
if (thresholdType != cv::THRESH_TRUNC && thresholdType != cv::THRESH_TOZERO &&
thresholdType != cv::THRESH_TOZERO_INV)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
if (depth != CV_8U && depth != CV_16S && depth != CV_32F)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
int roi_width = width * cn; // threshold is elementwise, so channels fold into the width
int roi_height = height;
int elemSize1 = (depth == CV_8U) ? 1 : (depth == CV_16S) ? 2 : 4;
if (src_step == (size_t)roi_width * elemSize1 && dst_step == (size_t)roi_width * elemSize1)
{
roi_width *= roi_height;
roi_height = 1;
src_step = dst_step = (size_t)roi_width * elemSize1;
}
IppiSize sz = { roi_width, roi_height };
const bool inplace = (src_data == dst_data);
IppStatus status = ippStsErr;
CV_SUPPRESS_DEPRECATED_START
switch (depth)
{
case CV_8U:
{
Ipp8u t = (Ipp8u)thresh;
switch (thresholdType)
{
case cv::THRESH_TRUNC:
if (inplace)
status = CV_INSTRUMENT_FUN_IPP(ippiThreshold_GT_8u_C1IR, dst_data, (int)dst_step, sz, t);
if (!inplace || status < 0)
status = CV_INSTRUMENT_FUN_IPP(ippiThreshold_GT_8u_C1R, src_data, (int)src_step, dst_data, (int)dst_step, sz, t);
break;
case cv::THRESH_TOZERO:
if (inplace)
status = CV_INSTRUMENT_FUN_IPP(ippiThreshold_LTVal_8u_C1IR, dst_data, (int)dst_step, sz, t + 1, 0);
if (!inplace || status < 0)
status = CV_INSTRUMENT_FUN_IPP(ippiThreshold_LTVal_8u_C1R, src_data, (int)src_step, dst_data, (int)dst_step, sz, t + 1, 0);
break;
case cv::THRESH_TOZERO_INV:
if (inplace)
status = CV_INSTRUMENT_FUN_IPP(ippiThreshold_GTVal_8u_C1IR, dst_data, (int)dst_step, sz, t, 0);
if (!inplace || status < 0)
status = CV_INSTRUMENT_FUN_IPP(ippiThreshold_GTVal_8u_C1R, src_data, (int)src_step, dst_data, (int)dst_step, sz, t, 0);
break;
}
break;
}
case CV_16S:
{
const Ipp16s* src = (const Ipp16s*)src_data;
Ipp16s* dst = (Ipp16s*)dst_data;
Ipp16s t = (Ipp16s)thresh;
switch (thresholdType)
{
case cv::THRESH_TRUNC:
if (inplace)
status = CV_INSTRUMENT_FUN_IPP(ippiThreshold_GT_16s_C1IR, dst, (int)dst_step, sz, t);
if (!inplace || status < 0)
status = CV_INSTRUMENT_FUN_IPP(ippiThreshold_GT_16s_C1R, src, (int)src_step, dst, (int)dst_step, sz, t);
break;
case cv::THRESH_TOZERO:
if (inplace)
status = CV_INSTRUMENT_FUN_IPP(ippiThreshold_LTVal_16s_C1IR, dst, (int)dst_step, sz, t + 1, 0);
if (!inplace || status < 0)
status = CV_INSTRUMENT_FUN_IPP(ippiThreshold_LTVal_16s_C1R, src, (int)src_step, dst, (int)dst_step, sz, t + 1, 0);
break;
case cv::THRESH_TOZERO_INV:
if (inplace)
status = CV_INSTRUMENT_FUN_IPP(ippiThreshold_GTVal_16s_C1IR, dst, (int)dst_step, sz, t, 0);
if (!inplace || status < 0)
status = CV_INSTRUMENT_FUN_IPP(ippiThreshold_GTVal_16s_C1R, src, (int)src_step, dst, (int)dst_step, sz, t, 0);
break;
}
break;
}
case CV_32F:
{
const Ipp32f* src = (const Ipp32f*)src_data;
Ipp32f* dst = (Ipp32f*)dst_data;
Ipp32f t = (Ipp32f)thresh;
switch (thresholdType)
{
case cv::THRESH_TRUNC:
status = CV_INSTRUMENT_FUN_IPP(ippiThreshold_GT_32f_C1R, src, (int)src_step, dst, (int)dst_step, sz, t);
break;
case cv::THRESH_TOZERO:
status = CV_INSTRUMENT_FUN_IPP(ippiThreshold_LTVal_32f_C1R, src, (int)src_step, dst, (int)dst_step, sz, nextafterf(t, std::numeric_limits<float>::infinity()), 0);
break;
case cv::THRESH_TOZERO_INV:
status = CV_INSTRUMENT_FUN_IPP(ippiThreshold_GTVal_32f_C1R, src, (int)src_step, dst, (int)dst_step, sz, t, 0);
break;
}
break;
}
}
CV_SUPPRESS_DEPRECATED_END
return status >= 0 ? CV_HAL_ERROR_OK : CV_HAL_ERROR_NOT_IMPLEMENTED;
}
#endif // IPP_VERSION_X100 >= 700
+1 -1
View File
@@ -235,7 +235,7 @@ int ipp_hal_warpPerspective(int src_type, const uchar *src_data, size_t src_step
{{0, 0}, {0, 0}, {0, 0}, {0, 1}}, //16U
{{1, 1}, {0, 0}, {1, 0}, {1, 1}}, //16S
{{1, 1}, {0, 0}, {1, 0}, {1, 1}}, //32S
{{0, 0}, {0, 0}, {0, 0}, {1, 0}}, //32F
{{0, 0}, {0, 0}, {0, 0}, {0, 0}}, //32F
{{0, 0}, {0, 0}, {0, 0}, {0, 0}}}; //64F
#endif
+179
View File
@@ -119,6 +119,8 @@ template<> struct rvv<RVV_U8M1>
{
static inline vfloat32m4_t vcvt0(vuint8m1_t a, size_t b) { return __riscv_vfcvt_f(__riscv_vzext_vf4(a, b), b); }
static inline vuint8m1_t vcvt1(vfloat32m4_t a, size_t b) { return __riscv_vnclipu(__riscv_vfncvt_xu(a, b), 0, __RISCV_VXRM_RNU, b); }
static inline vint32m4_t vwiden(vuint8m1_t a, size_t b) { return __riscv_vreinterpret_v_u32m4_i32m4(__riscv_vzext_vf4(a, b)); }
static inline vuint8m1_t vnarrow(vint32m4_t a, size_t b) { return __riscv_vncvt_x(__riscv_vncvt_x(__riscv_vreinterpret_v_i32m4_u32m4(a), b), b); }
static inline vuint8m1_t vloxei(const uchar* a, vuint16m2_t b, size_t c) { return __riscv_vloxei16_v_u8m1(a, b, c); }
static inline void vloxseg2ei(const uchar* a, vuint16m2_t b, size_t c, vuint8m1_t& x, vuint8m1_t& y) { auto src = __riscv_vloxseg2ei16_v_u8m1x2(a, b, c); x = __riscv_vget_v_u8m1x2_u8m1(src, 0); y = __riscv_vget_v_u8m1x2_u8m1(src, 1); }
static inline void vloxseg3ei(const uchar* a, vuint16m2_t b, size_t c, vuint8m1_t& x, vuint8m1_t& y, vuint8m1_t& z) { auto src = __riscv_vloxseg3ei16_v_u8m1x3(a, b, c); x = __riscv_vget_v_u8m1x3_u8m1(src, 0); y = __riscv_vget_v_u8m1x3_u8m1(src, 1); z = __riscv_vget_v_u8m1x3_u8m1(src, 2); }
@@ -165,6 +167,8 @@ template<> struct rvv<RVV_U8MF2>
{
static inline vfloat32m2_t vcvt0(vuint8mf2_t a, size_t b) { return __riscv_vfcvt_f(__riscv_vzext_vf4(a, b), b); }
static inline vuint8mf2_t vcvt1(vfloat32m2_t a, size_t b) { return __riscv_vnclipu(__riscv_vfncvt_xu(a, b), 0, __RISCV_VXRM_RNU, b); }
static inline vint32m2_t vwiden(vuint8mf2_t a, size_t b) { return __riscv_vreinterpret_v_u32m2_i32m2(__riscv_vzext_vf4(a, b)); }
static inline vuint8mf2_t vnarrow(vint32m2_t a, size_t b) { return __riscv_vncvt_x(__riscv_vncvt_x(__riscv_vreinterpret_v_i32m2_u32m2(a), b), b); }
static inline vuint8mf2_t vloxei(const uchar* a, vuint16m1_t b, size_t c) { return __riscv_vloxei16_v_u8mf2(a, b, c); }
static inline void vloxseg2ei(const uchar* a, vuint16m1_t b, size_t c, vuint8mf2_t& x, vuint8mf2_t& y) { auto src = __riscv_vloxseg2ei16_v_u8mf2x2(a, b, c); x = __riscv_vget_v_u8mf2x2_u8mf2(src, 0); y = __riscv_vget_v_u8mf2x2_u8mf2(src, 1); }
static inline void vloxseg3ei(const uchar* a, vuint16m1_t b, size_t c, vuint8mf2_t& x, vuint8mf2_t& y, vuint8mf2_t& z) { auto src = __riscv_vloxseg3ei16_v_u8mf2x3(a, b, c); x = __riscv_vget_v_u8mf2x3_u8mf2(src, 0); y = __riscv_vget_v_u8mf2x3_u8mf2(src, 1); z = __riscv_vget_v_u8mf2x3_u8mf2(src, 2); }
@@ -332,6 +336,150 @@ static inline int resizeLinear(int start, int end, const uchar *src_data, size_t
return CV_HAL_ERROR_OK;
}
static const int INTER_RESIZE_COEF_BITS = 11;
static const int INTER_RESIZE_COEF_SCALE = 1 << INTER_RESIZE_COEF_BITS;
// Bit-exact fixed-point vertical+horizontal linear combine for one channel, matching the reference
// HResizeLinear<uchar,int,short,INTER_RESIZE_COEF_SCALE> + VResizeLinear<uchar,int,short,
// FixedPtCast<int,uchar,INTER_RESIZE_COEF_BITS*2>> in modules/imgproc/src/resize.cpp.
// Sxy are the four widened (int32) source corners; a0/a1 the horizontal weights (per column),
// b0/b1 the vertical weights (per row). The staged >>4 / >>16 / >>2 shifts (total 22) reproduce the
// reference exactly and keep the intermediates within int32.
template<typename VI>
static inline VI resizeLinearU8Combine(VI S00, VI S01, VI S10, VI S11, VI a0, VI a1, int b0, int b1, size_t vl)
{
VI h0 = __riscv_vmacc(__riscv_vmul(S00, a0, vl), S01, a1, vl); // S[y0][x0]*a0 + S[y0][x1]*a1
VI h1 = __riscv_vmacc(__riscv_vmul(S10, a0, vl), S11, a1, vl); // S[y1][x0]*a0 + S[y1][x1]*a1
h0 = __riscv_vsra(__riscv_vmul(__riscv_vsra(h0, 4, vl), b0, vl), 16, vl); // (b0*(h0>>4))>>16
h1 = __riscv_vsra(__riscv_vmul(__riscv_vsra(h1, 4, vl), b1, vl), 16, vl); // (b1*(h1>>4))>>16
return __riscv_vsra(__riscv_vadd(__riscv_vadd(h0, h1, vl), 2, vl), 2, vl); // (t0 + t1 + 2) >> 2
}
// the algorithm is copied from imgproc/src/resize.cpp, HResizeLinear + VResizeLinear for uchar.
// The generic resizeLinear<> above computes in float, which is bit-exact only for 16U/32F; 8U
// INTER_LINEAR must use this fixed-point path to match the reference (float drift breaks tight
// consumers such as DNN blobFromImage preprocessing, issue #28870).
template<typename helper, int cn>
static inline int resizeLinearU8(int start, int end, const uchar *src_data, size_t src_step, int src_height, uchar *dst_data, size_t dst_step, int dst_width, double scale_y, const ushort* x_ofs0, const ushort* x_ofs1, const int* ialpha0, const int* ialpha1)
{
for (int i = start; i < end; i++)
{
float my = (i + 0.5) * scale_y - 0.5;
int y_ofs = static_cast<int>(std::floor(my));
my -= y_ofs;
int y_ofs0 = std::min(std::max(y_ofs , 0), src_height - 1);
int y_ofs1 = std::min(std::max(y_ofs + 1, 0), src_height - 1);
int b0 = saturate_cast<short>((1.f - my) * INTER_RESIZE_COEF_SCALE);
int b1 = saturate_cast<short>(my * INTER_RESIZE_COEF_SCALE);
const uchar* S0 = src_data + y_ofs0 * src_step;
const uchar* S1 = src_data + y_ofs1 * src_step;
int vl;
switch (cn)
{
case 1:
for (int j = 0; j < dst_width; j += vl)
{
vl = helper::setvl(dst_width - j);
auto ptr0 = RVV_SameLen<ushort, helper>::vload(x_ofs0 + j, vl);
auto ptr1 = RVV_SameLen<ushort, helper>::vload(x_ofs1 + j, vl);
auto a0 = RVV_SameLen<int, helper>::vload(ialpha0 + j, vl);
auto a1 = RVV_SameLen<int, helper>::vload(ialpha1 + j, vl);
auto v00 = rvv<helper>::vwiden(rvv<helper>::vloxei(S0, ptr0, vl), vl);
auto v01 = rvv<helper>::vwiden(rvv<helper>::vloxei(S0, ptr1, vl), vl);
auto v02 = rvv<helper>::vwiden(rvv<helper>::vloxei(S1, ptr0, vl), vl);
auto v03 = rvv<helper>::vwiden(rvv<helper>::vloxei(S1, ptr1, vl), vl);
auto d0 = resizeLinearU8Combine(v00, v01, v02, v03, a0, a1, b0, b1, vl);
helper::vstore(reinterpret_cast<typename helper::ElemType*>(dst_data + i * dst_step) + j, rvv<helper>::vnarrow(d0, vl), vl);
}
break;
case 2:
for (int j = 0; j < dst_width; j += vl)
{
vl = helper::setvl(dst_width - j);
auto ptr0 = RVV_SameLen<ushort, helper>::vload(x_ofs0 + j, vl);
auto ptr1 = RVV_SameLen<ushort, helper>::vload(x_ofs1 + j, vl);
auto a0 = RVV_SameLen<int, helper>::vload(ialpha0 + j, vl);
auto a1 = RVV_SameLen<int, helper>::vload(ialpha1 + j, vl);
typename helper::VecType s0, s1;
rvv<helper>::vloxseg2ei(S0, ptr0, vl, s0, s1);
auto v00 = rvv<helper>::vwiden(s0, vl), v10 = rvv<helper>::vwiden(s1, vl);
rvv<helper>::vloxseg2ei(S0, ptr1, vl, s0, s1);
auto v01 = rvv<helper>::vwiden(s0, vl), v11 = rvv<helper>::vwiden(s1, vl);
rvv<helper>::vloxseg2ei(S1, ptr0, vl, s0, s1);
auto v02 = rvv<helper>::vwiden(s0, vl), v12 = rvv<helper>::vwiden(s1, vl);
rvv<helper>::vloxseg2ei(S1, ptr1, vl, s0, s1);
auto v03 = rvv<helper>::vwiden(s0, vl), v13 = rvv<helper>::vwiden(s1, vl);
auto d0 = resizeLinearU8Combine(v00, v01, v02, v03, a0, a1, b0, b1, vl);
auto d1 = resizeLinearU8Combine(v10, v11, v12, v13, a0, a1, b0, b1, vl);
rvv<helper>::vsseg2e(reinterpret_cast<typename helper::ElemType*>(dst_data + i * dst_step) + j * 2, vl, rvv<helper>::vnarrow(d0, vl), rvv<helper>::vnarrow(d1, vl));
}
break;
case 3:
for (int j = 0; j < dst_width; j += vl)
{
vl = helper::setvl(dst_width - j);
auto ptr0 = RVV_SameLen<ushort, helper>::vload(x_ofs0 + j, vl);
auto ptr1 = RVV_SameLen<ushort, helper>::vload(x_ofs1 + j, vl);
auto a0 = RVV_SameLen<int, helper>::vload(ialpha0 + j, vl);
auto a1 = RVV_SameLen<int, helper>::vload(ialpha1 + j, vl);
typename helper::VecType s0, s1, s2;
rvv<helper>::vloxseg3ei(S0, ptr0, vl, s0, s1, s2);
auto v00 = rvv<helper>::vwiden(s0, vl), v10 = rvv<helper>::vwiden(s1, vl), v20 = rvv<helper>::vwiden(s2, vl);
rvv<helper>::vloxseg3ei(S0, ptr1, vl, s0, s1, s2);
auto v01 = rvv<helper>::vwiden(s0, vl), v11 = rvv<helper>::vwiden(s1, vl), v21 = rvv<helper>::vwiden(s2, vl);
rvv<helper>::vloxseg3ei(S1, ptr0, vl, s0, s1, s2);
auto v02 = rvv<helper>::vwiden(s0, vl), v12 = rvv<helper>::vwiden(s1, vl), v22 = rvv<helper>::vwiden(s2, vl);
rvv<helper>::vloxseg3ei(S1, ptr1, vl, s0, s1, s2);
auto v03 = rvv<helper>::vwiden(s0, vl), v13 = rvv<helper>::vwiden(s1, vl), v23 = rvv<helper>::vwiden(s2, vl);
auto d0 = resizeLinearU8Combine(v00, v01, v02, v03, a0, a1, b0, b1, vl);
auto d1 = resizeLinearU8Combine(v10, v11, v12, v13, a0, a1, b0, b1, vl);
auto d2 = resizeLinearU8Combine(v20, v21, v22, v23, a0, a1, b0, b1, vl);
rvv<helper>::vsseg3e(reinterpret_cast<typename helper::ElemType*>(dst_data + i * dst_step) + j * 3, vl, rvv<helper>::vnarrow(d0, vl), rvv<helper>::vnarrow(d1, vl), rvv<helper>::vnarrow(d2, vl));
}
break;
case 4:
for (int j = 0; j < dst_width; j += vl)
{
vl = helper::setvl(dst_width - j);
auto ptr0 = RVV_SameLen<ushort, helper>::vload(x_ofs0 + j, vl);
auto ptr1 = RVV_SameLen<ushort, helper>::vload(x_ofs1 + j, vl);
auto a0 = RVV_SameLen<int, helper>::vload(ialpha0 + j, vl);
auto a1 = RVV_SameLen<int, helper>::vload(ialpha1 + j, vl);
typename helper::VecType s0, s1, s2, s3;
rvv<helper>::vloxseg4ei(S0, ptr0, vl, s0, s1, s2, s3);
auto v00 = rvv<helper>::vwiden(s0, vl), v10 = rvv<helper>::vwiden(s1, vl), v20 = rvv<helper>::vwiden(s2, vl), v30 = rvv<helper>::vwiden(s3, vl);
rvv<helper>::vloxseg4ei(S0, ptr1, vl, s0, s1, s2, s3);
auto v01 = rvv<helper>::vwiden(s0, vl), v11 = rvv<helper>::vwiden(s1, vl), v21 = rvv<helper>::vwiden(s2, vl), v31 = rvv<helper>::vwiden(s3, vl);
rvv<helper>::vloxseg4ei(S1, ptr0, vl, s0, s1, s2, s3);
auto v02 = rvv<helper>::vwiden(s0, vl), v12 = rvv<helper>::vwiden(s1, vl), v22 = rvv<helper>::vwiden(s2, vl), v32 = rvv<helper>::vwiden(s3, vl);
rvv<helper>::vloxseg4ei(S1, ptr1, vl, s0, s1, s2, s3);
auto v03 = rvv<helper>::vwiden(s0, vl), v13 = rvv<helper>::vwiden(s1, vl), v23 = rvv<helper>::vwiden(s2, vl), v33 = rvv<helper>::vwiden(s3, vl);
auto d0 = resizeLinearU8Combine(v00, v01, v02, v03, a0, a1, b0, b1, vl);
auto d1 = resizeLinearU8Combine(v10, v11, v12, v13, a0, a1, b0, b1, vl);
auto d2 = resizeLinearU8Combine(v20, v21, v22, v23, a0, a1, b0, b1, vl);
auto d3 = resizeLinearU8Combine(v30, v31, v32, v33, a0, a1, b0, b1, vl);
rvv<helper>::vsseg4e(reinterpret_cast<typename helper::ElemType*>(dst_data + i * dst_step) + j * 4, vl, rvv<helper>::vnarrow(d0, vl), rvv<helper>::vnarrow(d1, vl), rvv<helper>::vnarrow(d2, vl), rvv<helper>::vnarrow(d3, vl));
}
break;
default:
return CV_HAL_ERROR_NOT_IMPLEMENTED;
}
}
return CV_HAL_ERROR_OK;
}
template<int cn>
static inline int resizeLinearExact(int start, int end, const uchar *src_data, size_t src_step, int src_height, uchar *dst_data, size_t dst_step, int dst_width, double scale_y, const ushort* x_ofs0, const ushort* x_ofs1, const ushort* x_val)
{
@@ -833,6 +981,37 @@ static inline int resizeLinear(int src_type, const uchar *src_data, size_t src_s
return invoke(dst_height, {resizeLinearExact<4>}, src_data, src_step, src_height, dst_data, dst_step, dst_width, scale_y, x_ofs0.data(), x_ofs1.data(), x_val.data());
}
}
else if (CV_MAT_DEPTH(src_type) == CV_8U)
{
// 8U INTER_LINEAR must be bit-exact fixed-point to match the reference implementation;
// computing it in float drifts and breaks tight consumers (e.g. DNN preprocessing, #28870).
std::vector<int> ialpha0(dst_width), ialpha1(dst_width);
for (int i = 0; i < dst_width; i++)
{
float fx = (float)((i + 0.5) * scale_x - 0.5);
int x_ofs = static_cast<int>(std::floor(fx));
fx -= x_ofs;
if (x_ofs < 0) { fx = 0; x_ofs = 0; }
if (x_ofs >= src_width - 1) { fx = 0; x_ofs = src_width - 1; }
x_ofs0[i] = static_cast<ushort>(x_ofs) * cn;
x_ofs1[i] = static_cast<ushort>(std::min(x_ofs + 1, src_width - 1)) * cn;
ialpha0[i] = saturate_cast<short>((1.f - fx) * INTER_RESIZE_COEF_SCALE);
ialpha1[i] = saturate_cast<short>(fx * INTER_RESIZE_COEF_SCALE);
}
switch (src_type)
{
case CV_8UC1:
return invoke(dst_height, {resizeLinearU8<RVV_U8M1, 1>}, src_data, src_step, src_height, dst_data, dst_step, dst_width, scale_y, x_ofs0.data(), x_ofs1.data(), ialpha0.data(), ialpha1.data());
case CV_8UC2:
return invoke(dst_height, {resizeLinearU8<RVV_U8M1, 2>}, src_data, src_step, src_height, dst_data, dst_step, dst_width, scale_y, x_ofs0.data(), x_ofs1.data(), ialpha0.data(), ialpha1.data());
case CV_8UC3:
return invoke(dst_height, {resizeLinearU8<RVV_U8MF2, 3>}, src_data, src_step, src_height, dst_data, dst_step, dst_width, scale_y, x_ofs0.data(), x_ofs1.data(), ialpha0.data(), ialpha1.data());
case CV_8UC4:
return invoke(dst_height, {resizeLinearU8<RVV_U8MF2, 4>}, src_data, src_step, src_height, dst_data, dst_step, dst_width, scale_y, x_ofs0.data(), x_ofs1.data(), ialpha0.data(), ialpha1.data());
}
}
else
{
std::vector<float> x_val(dst_width);
@@ -197,7 +197,6 @@ T* allocSingletonNew() { return new(allocSingletonNewBuffer(sizeof(T))) T(); }
// Temporary disabled named IPP region. Performance
#define IPP_DISABLE_PERF_COPYMAKE 1 // performance variations
#define IPP_DISABLE_PERF_TRUE_DIST_MT 1 // cv::distanceTransform OpenCV MT performance is better
#define IPP_DISABLE_PERF_CANNY_MT 1 // cv::Canny OpenCV MT performance is better
#ifdef HAVE_IPP
#include "ippversion.h"
+63 -52
View File
@@ -6,11 +6,8 @@
#include "opencv2/core/mat.hpp"
#include "opencl_kernels_core.hpp"
#undef HAVE_IPP
#undef CV_IPP_RUN_FAST
#define CV_IPP_RUN_FAST(f, ...)
#undef CV_IPP_RUN
#define CV_IPP_RUN(c, f, ...)
#define IPP_DISABLE_REDUCE 1
#define IPP_DISABLE_SORT 0
/*************************************************************************************************\
Matrix Operations
@@ -498,7 +495,7 @@ typedef void (*ReduceFunc)( const Mat& src, Mat& dst );
#define reduceMinR32f reduceR_<float, float, OpMin<float> >
#define reduceMinR64f reduceR_<double,double,OpMin<double> >
#ifdef HAVE_IPP
#if defined(HAVE_IPP) && !IPP_DISABLE_REDUCE
static inline bool ipp_reduceSumC_8u16u16s32f_64f(const cv::Mat& srcmat, cv::Mat& dstmat)
{
int sstep = (int)srcmat.step, stype = srcmat.type(),
@@ -587,7 +584,7 @@ static inline void reduceSumC_8u16u16s32f_64f(const cv::Mat& srcmat, cv::Mat& ds
#define reduceSum2C32f32f reduceC_<float, float, OpAddSqr<float>, OpSqr<float> >
#define reduceSum2C64f64f reduceC_<double,double,OpAddSqr<double>,OpSqr<double> >
#ifdef HAVE_IPP
#if defined(HAVE_IPP) && !IPP_DISABLE_REDUCE
#define reduceSumC8u64f reduceSumC_8u16u16s32f_64f
#define reduceSumC16u64f reduceSumC_8u16u16s32f_64f
#define reduceSumC16s64f reduceSumC_8u16u16s32f_64f
@@ -597,14 +594,14 @@ static inline void reduceSumC_8u16u16s32f_64f(const cv::Mat& srcmat, cv::Mat& ds
#define reduceSumC16u64f reduceC_<ushort,double,OpAdd<double> >
#define reduceSumC16s64f reduceC_<short, double,OpAdd<double> >
#define reduceSumC32f64f reduceC_<float, double,OpAdd<double> >
#endif
#define reduceSum2C8u64f reduceC_<uchar, double,OpAddSqr<int>, OpSqr<int> >
#define reduceSum2C16u64f reduceC_<ushort,double,OpAddSqr<double>,OpSqr<double> >
#define reduceSum2C16s64f reduceC_<short, double,OpAddSqr<double>,OpSqr<double> >
#define reduceSum2C32f64f reduceC_<float, double,OpAddSqr<double>,OpSqr<double> >
#endif
#ifdef HAVE_IPP
#if defined(HAVE_IPP) && !IPP_DISABLE_REDUCE
#define REDUCE_OP(favor, optype, type1, type2) \
static inline bool ipp_reduce##optype##C##favor(const cv::Mat& srcmat, cv::Mat& dstmat) \
{ \
@@ -629,7 +626,7 @@ static inline void reduce##optype##C##favor(const cv::Mat& srcmat, cv::Mat& dstm
}
#endif
#ifdef HAVE_IPP
#if defined(HAVE_IPP) && !IPP_DISABLE_REDUCE
REDUCE_OP(8u, Max, uchar, uchar)
REDUCE_OP(16u, Max, ushort, ushort)
REDUCE_OP(16s, Max, short, short)
@@ -642,7 +639,7 @@ REDUCE_OP(32f, Max, float, float)
#endif
#define reduceMaxC64f reduceC_<double,double,OpMax<double> >
#ifdef HAVE_IPP
#if defined(HAVE_IPP) && !IPP_DISABLE_REDUCE
REDUCE_OP(8u, Min, uchar, uchar)
REDUCE_OP(16u, Min, ushort, ushort)
REDUCE_OP(16s, Min, short, short)
@@ -1037,7 +1034,7 @@ template<typename T> static void sort_( const Mat& src, Mat& dst, int flags )
}
#ifdef HAVE_IPP
#if defined(HAVE_IPP) && !IPP_DISABLE_SORT
typedef IppStatus (CV_STDCALL *IppSortFunc)(void *pSrcDst, int len, Ipp8u *pBuffer);
static IppSortFunc getSortFunc(int depth, bool sortDescending)
@@ -1074,54 +1071,64 @@ static bool ipp_sort(const Mat& src, Mat& dst, int flags)
if(!ippsSortRadix_I)
return false;
if(sortRows)
{
AutoBuffer<Ipp8u> buffer;
int bufferSize;
if(ippsSortRadixGetBufferSize(src.cols, type, &bufferSize) < 0)
return false;
buffer.allocate(bufferSize);
if(!inplace)
src.copyTo(dst);
for(int i = 0; i < dst.rows; i++)
{
if(CV_INSTRUMENT_FUN_IPP(ippsSortRadix_I, (void*)dst.ptr(i), dst.cols, buffer.data()) < 0)
return false;
}
}
int n, len;
if( sortRows )
n = src.rows, len = src.cols;
else
n = src.cols, len = src.rows;
int bufferSize;
if(ippsSortRadixGetBufferSize(len, type, &bufferSize) < 0)
return false;
// Each row/column sorts independently, so parallelize over n like sort_ does.
// IPP scratch (buffer) and per-column temporaries are thread-local; a shared flag
// records IPP failures since the lambda cannot return from ipp_sort.
volatile bool ok = true;
parallel_for_(Range(0, n), [&](const Range& range)
{
AutoBuffer<Ipp8u> buffer;
int bufferSize;
if(ippsSortRadixGetBufferSize(src.rows, type, &bufferSize) < 0)
return false;
buffer.allocate(bufferSize);
Mat row(1, src.rows, src.type());
Mat srcSub;
Mat dstSub;
AutoBuffer<Ipp8u> buffer(bufferSize);
Mat row;
Rect subRect(0,0,1,src.rows);
if( !sortRows )
row.create(1, src.rows, src.type());
for(int i = 0; i < src.cols; i++)
for( int i = range.start; i < range.end; i++ )
{
subRect.x = i;
srcSub = Mat(src, subRect);
dstSub = Mat(dst, subRect);
srcSub.copyTo(row);
if( !ok )
break;
void* ptr;
if( sortRows )
{
uchar* dptr = dst.ptr(i);
if( !inplace )
memcpy(dptr, src.ptr(i), src.cols * src.elemSize());
ptr = dptr;
}
else
{
subRect.x = i;
Mat(src, subRect).copyTo(row);
ptr = row.ptr();
}
if(CV_INSTRUMENT_FUN_IPP(ippsSortRadix_I, (void*)row.ptr(), dst.rows, buffer.data()) < 0)
return false;
if( CV_INSTRUMENT_FUN_IPP(ippsSortRadix_I, ptr, len, buffer.data()) < 0 )
{
ok = false;
break;
}
row = row.reshape(1, dstSub.rows);
row.copyTo(dstSub);
if( !sortRows )
{
Mat dstSub(dst, subRect);
row = row.reshape(1, dstSub.rows);
row.copyTo(dstSub);
row = row.reshape(1, 1);
}
}
}
});
return true;
return ok;
}
#endif
@@ -1185,7 +1192,7 @@ template<typename T> static void sortIdx_( const Mat& src, Mat& dst, int flags )
}
}
#ifdef HAVE_IPP
#if defined(HAVE_IPP) && !IPP_DISABLE_SORT
typedef IppStatus (CV_STDCALL *IppSortIndexFunc)(const void* pSrc, Ipp32s srcStrideBytes, Ipp32s *pDstIndx, int len, Ipp8u *pBuffer);
static IppSortIndexFunc getSortIndexFunc(int depth, bool sortDescending)
@@ -1276,7 +1283,9 @@ void cv::sort( InputArray _src, OutputArray _dst, int flags )
CV_Assert( src.dims <= 2 && src.channels() == 1 );
_dst.createSameSize( src, src.type() );
Mat dst = _dst.getMat();
#if !IPP_DISABLE_SORT
CV_IPP_RUN_FAST(ipp_sort(src, dst, flags));
#endif
static SortFunc tab[CV_DEPTH_MAX] =
{
@@ -1301,7 +1310,9 @@ void cv::sortIdx( InputArray _src, OutputArray _dst, int flags )
_dst.createSameSize( src, CV_32S );
dst = _dst.getMat();
#if !IPP_DISABLE_SORT
CV_IPP_RUN_FAST(ipp_sortIdx(src, dst, flags));
#endif
static SortFunc tab[CV_DEPTH_MAX] =
{
@@ -832,7 +832,8 @@ CV_EXPORTS_W Vec3d RQDecomp3x3( InputArray src, OutputArray mtxR, OutputArray mt
@param projMatrix 3x4 input projection matrix P.
@param cameraMatrix Output 3x3 camera intrinsic matrix \f$\cameramatrix{A}\f$.
@param rotMatrix Output 3x3 external rotation matrix R.
@param transVect Output 4x1 translation vector T.
@param transVect Output 4x1 vector representing the camera position in homogeneous coordinates.
To obtain the translation vector, use t = -rotMatrix * transVect[:3]
@param rotMatrixX Optional 3x3 rotation matrix around x-axis.
@param rotMatrixY Optional 3x3 rotation matrix around y-axis.
@param rotMatrixZ Optional 3x3 rotation matrix around z-axis.
+6 -4
View File
@@ -2178,9 +2178,11 @@ with the WARP_RELATIVE_MAP flag :
where values of pixels with non-integer coordinates are computed using one of available
interpolation methods. \f$map_x\f$ and \f$map_y\f$ can be encoded as separate floating-point maps
in \f$map_1\f$ and \f$map_2\f$ respectively, or interleaved floating-point maps of \f$(x,y)\f$ in
\f$map_1\f$, or fixed-point maps created by using #convertMaps. The reason you might want to
convert from floating to fixed-point representations of a map is that they can yield much faster
(\~2x) remapping operations. In the converted case, \f$map_1\f$ contains pairs (cvFloor(x),
\f$map_1\f$, or fixed-point maps created by using #convertMaps. Fixed-point maps
use a more compact representation, which can reduce memory bandwidth and benefit
repeated remap calls that reuse the same map. Performance gains vary by hardware
and are typically modest; measure before converting. In the converted case,
\f$map_1\f$ contains pairs (cvFloor(x),
cvFloor(y)) and \f$map_2\f$ contains indices in a table of interpolation coefficients.
This function cannot operate in-place.
@@ -2189,7 +2191,7 @@ This function cannot operate in-place.
@param dst Destination image. It has the same size as map1 and the same type as src .
@param map1 The first map of either (x,y) points or just x values having the type CV_16SC2 ,
CV_32FC1, or CV_32FC2. See #convertMaps for details on converting a floating point
representation to fixed-point for speed.
representation to fixed-point.
@param map2 The second map of y values having the type CV_16UC1, CV_32FC1, or none (empty map
if map1 is (x,y) points), respectively.
@param interpolation Interpolation method (see #InterpolationFlags). The methods #INTER_AREA
+2 -82
View File
@@ -48,85 +48,6 @@
namespace cv
{
#ifdef HAVE_IPP
static bool ipp_Canny(const Mat& src , const Mat& dx_, const Mat& dy_, Mat& dst, float low, float high, bool L2gradient, int aperture_size)
{
#ifdef HAVE_IPP_IW
CV_INSTRUMENT_REGION_IPP();
#if IPP_DISABLE_PERF_CANNY_MT
if(cv::getNumThreads()>1)
return false;
#endif
::ipp::IwiSize size(dst.cols, dst.rows);
IppDataType type = ippiGetDataType(dst.depth());
int channels = dst.channels();
IppNormType norm = (L2gradient)?ippNormL2:ippNormL1;
if(size.width <= 3 || size.height <= 3)
return false;
if(channels != 1)
return false;
if(type != ipp8u)
return false;
if(src.empty())
{
try
{
::ipp::IwiImage iwSrcDx;
::ipp::IwiImage iwSrcDy;
::ipp::IwiImage iwDst;
ippiGetImage(dx_, iwSrcDx);
ippiGetImage(dy_, iwSrcDy);
ippiGetImage(dst, iwDst);
CV_INSTRUMENT_FUN_IPP(::ipp::iwiFilterCannyDeriv, iwSrcDx, iwSrcDy, iwDst, low, high, ::ipp::IwiFilterCannyDerivParams(norm));
}
catch (const ::ipp::IwException &)
{
return false;
}
}
else
{
IppiMaskSize kernel;
if(aperture_size == 3)
kernel = ippMskSize3x3;
else if(aperture_size == 5)
kernel = ippMskSize5x5;
else
return false;
try
{
::ipp::IwiImage iwSrc;
::ipp::IwiImage iwDst;
ippiGetImage(src, iwSrc);
ippiGetImage(dst, iwDst);
CV_INSTRUMENT_FUN_IPP(::ipp::iwiFilterCanny, iwSrc, iwDst, low, high, ::ipp::IwiFilterCannyParams(ippFilterSobel, kernel, norm), ippBorderRepl);
}
catch (const ::ipp::IwException &)
{
return false;
}
}
return true;
#else
CV_UNUSED(src); CV_UNUSED(dx_); CV_UNUSED(dy_); CV_UNUSED(dst); CV_UNUSED(low); CV_UNUSED(high); CV_UNUSED(L2gradient); CV_UNUSED(aperture_size);
return false;
#endif
}
#endif
#ifdef HAVE_OPENCL
template <bool useCustomDeriv>
@@ -803,8 +724,6 @@ void Canny( InputArray _src, OutputArray _dst,
CALL_HAL(canny, cv_hal_canny, src.data, src.step, dst.data, dst.step, src.cols, src.rows, src.channels(),
low_thresh, high_thresh, aperture_size, L2gradient);
CV_IPP_RUN_FAST(ipp_Canny(src, Mat(), Mat(), dst, (float)low_thresh, (float)high_thresh, L2gradient, aperture_size))
if (L2gradient)
{
low_thresh = std::min(32767.0, low_thresh);
@@ -879,7 +798,8 @@ void Canny( InputArray _dx, InputArray _dy, OutputArray _dst,
Mat dx = _dx.getMat();
Mat dy = _dy.getMat();
CV_IPP_RUN_FAST(ipp_Canny(Mat(), dx, dy, dst, (float)low_thresh, (float)high_thresh, L2gradient, 0))
CALL_HAL(canny_deriv, cv_hal_canny_deriv, dx.ptr<short>(), dx.step, dy.ptr<short>(), dy.step,
dst.data, dst.step, dx.cols, dx.rows, dx.channels(), low_thresh, high_thresh, L2gradient);
if (L2gradient)
{
+9 -86
View File
@@ -40,6 +40,7 @@
//
//M*/
#include "precomp.hpp"
#include "hal_replacement.hpp"
namespace cv
{
@@ -1004,19 +1005,8 @@ static void distanceTransform_L1_8U(InputArray _src, OutputArray _dst)
_dst.create( src.size(), CV_8UC1);
Mat dst = _dst.getMat();
#ifdef HAVE_IPP
CV_IPP_CHECK()
{
IppiSize roi = { src.cols, src.rows };
Ipp32s pMetrics[2] = { 1, 2 }; //L1, 3x3 mask
if (CV_INSTRUMENT_FUN_IPP(ippiDistanceTransform_3x3_8u_C1R, src.ptr<uchar>(), (int)src.step, dst.ptr<uchar>(), (int)dst.step, roi, pMetrics) >= 0)
{
CV_IMPL_ADD(CV_IMPL_IPP);
return;
}
setIppErrorStatus();
}
#endif
CALL_HAL(distanceTransform, cv_hal_distanceTransform, src.ptr<uchar>(), src.step, dst.ptr<uchar>(), dst.step,
src.cols, src.rows, CV_8U, cv::DIST_L1, cv::DIST_MASK_3);
distanceATS_L1_8u(src, dst);
}
@@ -1055,53 +1045,8 @@ void cv::distanceTransform( InputArray _src, OutputArray _dst, OutputArray _labe
if( maskSize == cv::DIST_MASK_PRECISE )
{
#ifdef HAVE_IPP
CV_IPP_CHECK()
{
#if IPP_DISABLE_PERF_TRUE_DIST_MT
// IPP uses floats, but 4097 cannot be squared into a float
if((cv::getNumThreads()<=1 || (src.total()<(int)(1<<14))) &&
src.rows < 4097 && src.cols < 4097)
#endif
{
IppStatus status;
IppiSize roi = { src.cols, src.rows };
Ipp8u *pBuffer;
int bufSize=0;
status = ippiTrueDistanceTransformGetBufferSize_8u32f_C1R(roi, &bufSize);
if (status>=0)
{
pBuffer = (Ipp8u *)CV_IPP_MALLOC( bufSize );
status = CV_INSTRUMENT_FUN_IPP(ippiTrueDistanceTransform_8u32f_C1R, src.ptr<uchar>(), (int)src.step, dst.ptr<float>(), (int)dst.step, roi, pBuffer);
ippFree( pBuffer );
if (status>=0)
{
// https://github.com/opencv/opencv/issues/24082
// There is probably a rounding issue that leads to non-deterministic behavior
// between runs on positions closer to zeros by x-axis in straight direction.
// As a workaround, we detect the distances that expected to be exact
// number of pixels and round manually.
static const float correctionDiff = 1.0f / (1 << 11);
for (int i = 0; i < dst.rows; ++i)
{
float* row = dst.ptr<float>(i);
for (int j = 0; j < dst.cols; ++j)
{
float rounded = static_cast<float>(cvRound(row[j]));
if (fabs(row[j] - rounded) <= correctionDiff)
row[j] = rounded;
}
}
CV_IMPL_ADD(CV_IMPL_IPP);
return;
}
setIppErrorStatus();
}
}
}
#endif
CALL_HAL(distanceTransform, cv_hal_distanceTransform, src.ptr<uchar>(), src.step, dst.ptr<uchar>(), dst.step,
src.cols, src.rows, CV_32F, distType, cv::DIST_MASK_PRECISE);
trueDistTrans( src, dst );
return;
@@ -1121,38 +1066,16 @@ void cv::distanceTransform( InputArray _src, OutputArray _dst, OutputArray _labe
{
if( maskSize == cv::DIST_MASK_3 )
{
#if defined (HAVE_IPP) && (IPP_VERSION_X100 >= 700)
bool has_int_overflow = (int64)src.cols * src.rows >= INT_MAX;
if (!has_int_overflow && CV_IPP_CHECK_COND)
{
IppiSize roi = { src.cols, src.rows };
if (CV_INSTRUMENT_FUN_IPP(ippiDistanceTransform_3x3_8u32f_C1R, src.ptr<uchar>(), (int)src.step, dst.ptr<float>(), (int)dst.step, roi, _mask) >= 0)
{
CV_IMPL_ADD(CV_IMPL_IPP);
return;
}
setIppErrorStatus();
}
#endif
CALL_HAL(distanceTransform, cv_hal_distanceTransform, src.ptr<uchar>(), src.step, dst.ptr<uchar>(), dst.step,
src.cols, src.rows, CV_32F, distType, cv::DIST_MASK_3);
temp.create(size.height + border*2, size.width + border*2, CV_32SC1);
distanceTransform_3x3(src, temp, dst, _mask);
}
else
{
#if defined (HAVE_IPP) && (IPP_VERSION_X100 >= 700)
bool has_int_overflow = (int64)src.cols * src.rows >= INT_MAX;
if (!has_int_overflow && CV_IPP_CHECK_COND)
{
IppiSize roi = { src.cols, src.rows };
if (CV_INSTRUMENT_FUN_IPP(ippiDistanceTransform_5x5_8u32f_C1R, src.ptr<uchar>(), (int)src.step, dst.ptr<float>(), (int)dst.step, roi, _mask) >= 0)
{
CV_IMPL_ADD(CV_IMPL_IPP);
return;
}
setIppErrorStatus();
}
#endif
CALL_HAL(distanceTransform, cv_hal_distanceTransform, src.ptr<uchar>(), src.step, dst.ptr<uchar>(), dst.step,
src.cols, src.rows, CV_32F, distType, cv::DIST_MASK_5);
temp.create(size.height + border*2, size.width + border*2, CV_32SC1);
distanceTransform_5x5(src, temp, dst, _mask);
+65 -11
View File
@@ -1067,16 +1067,6 @@ inline int hal_ni_cvtRGBAtoMultipliedRGBA(const uchar * src_data, size_t src_ste
*/
inline int hal_ni_cvtMultipliedRGBAtoRGBA(const uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int width, int height) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
/** @brief Extract Y-plane from YUV 4:2:0 image.
@param src_data Source image data pointer (points to Y plane).
@param src_step Source step.
@param dst_data Destination data pointer.
@param dst_step Destination step.
@param width Image width.
@param height Image height (of the Y plane, not the full YUV image).
*/
inline int hal_ni_cvtColorYUV2Gray(const uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int width, int height) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
//! @cond IGNORED
#define cv_hal_cvtBGRtoBGR hal_ni_cvtBGRtoBGR
#define cv_hal_cvtBGRtoBGR5x5 hal_ni_cvtBGRtoBGR5x5
@@ -1110,7 +1100,6 @@ inline int hal_ni_cvtColorYUV2Gray(const uchar * src_data, size_t src_step, ucha
#define cv_hal_cvtOnePlaneBGRtoYUVApprox hal_ni_cvtOnePlaneBGRtoYUVApprox
#define cv_hal_cvtRGBAtoMultipliedRGBA hal_ni_cvtRGBAtoMultipliedRGBA
#define cv_hal_cvtMultipliedRGBAtoRGBA hal_ni_cvtMultipliedRGBAtoRGBA
#define cv_hal_cvtColorYUV2Gray hal_ni_cvtColorYUV2Gray
//! @endcond
/**
@@ -1252,6 +1241,24 @@ inline int hal_ni_threshold_otsu(const uchar* src_data, size_t src_step, uchar*
#define cv_hal_threshold_otsu hal_ni_threshold_otsu
//! @endcond
/**
@brief Calculates the distance to the closest zero pixel for each pixel of the source image
@param src_data Source image (8-bit single-channel) data
@param src_step Source image step
@param dst_data Destination image data
@param dst_step Destination image step
@param width Source image width
@param height Source image height
@param dst_type Type of the destination image (CV_8UC1 or CV_32FC1)
@param dist_type Type of distance (cv::DistanceTypes: DIST_L1, DIST_L2, DIST_C)
@param mask_size Size of the distance transform mask (cv::DistanceTransformMasks: DIST_MASK_3, DIST_MASK_5, DIST_MASK_PRECISE)
*/
inline int hal_ni_distanceTransform(const uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step, int width, int height, int dst_type, int dist_type, int mask_size) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
//! @cond IGNORED
#define cv_hal_distanceTransform hal_ni_distanceTransform
//! @endcond
/**
@brief Calculate box filter
@param src_data Source image data
@@ -1531,6 +1538,27 @@ inline int hal_ni_canny(const uchar* src_data, size_t src_step, uchar* dst_data,
#define cv_hal_canny hal_ni_canny
//! @endcond
/**
@brief Canny edge detector from image derivatives
@param dx_data Source image x-derivative data
@param dx_step Source image x-derivative step
@param dy_data Source image y-derivative data
@param dy_step Source image y-derivative step
@param dst_data Destination image data
@param dst_step Destination image step
@param width Source image width
@param height Source image height
@param cn Number of channels
@param lowThreshold low hresholds value
@param highThreshold high thresholds value
@param L2gradient Flag, indicating use L2 or L1 norma.
*/
inline int hal_ni_canny_deriv(const short* dx_data, size_t dx_step, const short* dy_data, size_t dy_step, uchar* dst_data, size_t dst_step, int width, int height, int cn, double lowThreshold, double highThreshold, bool L2gradient) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
//! @cond IGNORED
#define cv_hal_canny_deriv hal_ni_canny_deriv
//! @endcond
/**
@brief Calculates a histogram of a set of arrays
@param src_data Source imgage data
@@ -1551,6 +1579,32 @@ inline int hal_ni_calcHist(const uchar* src_data, size_t src_step, int src_type,
#define cv_hal_calcHist hal_ni_calcHist
//! @endcond
/**
@brief Compares a template against overlapped image regions.
@param src_data Source image (single-channel, CV_8U or CV_32F) data
@param src_step Source image step
@param src_width Source image width
@param src_height Source image height
@param templ_data Template image data (same type as source)
@param templ_step Template image step
@param templ_width Template image width
@param templ_height Template image height
@param result_data Destination map data (single-channel CV_32F, size (src_width-templ_width+1) x (src_height-templ_height+1))
@param result_step Destination map step
@param depth Depth of source and template images (CV_8U or CV_32F)
@param cn Number of channels
@param method Comparison method (cv::TemplateMatchModes)
@sa matchTemplate
*/
inline int hal_ni_matchTemplate(const uchar* src_data, size_t src_step, int src_width, int src_height,
const uchar* templ_data, size_t templ_step, int templ_width, int templ_height,
float* result_data, size_t result_step, int depth, int cn, int method)
{ return CV_HAL_ERROR_NOT_IMPLEMENTED; }
//! @cond IGNORED
#define cv_hal_matchTemplate hal_ni_matchTemplate
//! @endcond
//! @}
#if defined(__clang__)
+16 -130
View File
@@ -1034,135 +1034,6 @@ static void common_matchTemplate( Mat& img, Mat& templ, Mat& result, int method,
}
}
#if defined HAVE_IPP
namespace cv
{
typedef IppStatus (CV_STDCALL * ippimatchTemplate)(const void*, int, IppiSize, const void*, int, IppiSize, Ipp32f* , int , IppEnum , Ipp8u*);
static bool ipp_crossCorr(const Mat& src, const Mat& tpl, Mat& dst, bool normed)
{
CV_INSTRUMENT_REGION_IPP();
IppStatus status;
IppiSize srcRoiSize = {src.cols,src.rows};
IppiSize tplRoiSize = {tpl.cols,tpl.rows};
IppAutoBuffer<Ipp8u> buffer;
int bufSize=0;
int depth = src.depth();
ippimatchTemplate ippiCrossCorrNorm =
depth==CV_8U ? (ippimatchTemplate)ippiCrossCorrNorm_8u32f_C1R:
depth==CV_32F? (ippimatchTemplate)ippiCrossCorrNorm_32f_C1R: 0;
if (ippiCrossCorrNorm==0)
return false;
IppEnum funCfg = (IppEnum)(+ippAlgAuto | ippiROIValid);
if(normed)
funCfg |= ippiNorm;
else
funCfg |= ippiNormNone;
status = ippiCrossCorrNormGetBufferSize(srcRoiSize, tplRoiSize, funCfg, &bufSize);
if ( status < 0 )
return false;
buffer.allocate( bufSize );
status = CV_INSTRUMENT_FUN_IPP(ippiCrossCorrNorm, src.ptr(), (int)src.step, srcRoiSize, tpl.ptr(), (int)tpl.step, tplRoiSize, dst.ptr<Ipp32f>(), (int)dst.step, funCfg, buffer);
return status >= 0;
}
static bool ipp_sqrDistance(const Mat& src, const Mat& tpl, Mat& dst)
{
CV_INSTRUMENT_REGION_IPP();
IppStatus status;
IppiSize srcRoiSize = {src.cols,src.rows};
IppiSize tplRoiSize = {tpl.cols,tpl.rows};
IppAutoBuffer<Ipp8u> buffer;
int bufSize=0;
int depth = src.depth();
ippimatchTemplate ippiSqrDistanceNorm =
depth==CV_8U ? (ippimatchTemplate)ippiSqrDistanceNorm_8u32f_C1R:
depth==CV_32F? (ippimatchTemplate)ippiSqrDistanceNorm_32f_C1R: 0;
if (ippiSqrDistanceNorm==0)
return false;
IppEnum funCfg = (IppEnum)(+ippAlgAuto | ippiROIValid | ippiNormNone);
status = ippiSqrDistanceNormGetBufferSize(srcRoiSize, tplRoiSize, funCfg, &bufSize);
if ( status < 0 )
return false;
buffer.allocate( bufSize );
status = CV_INSTRUMENT_FUN_IPP(ippiSqrDistanceNorm, src.ptr(), (int)src.step, srcRoiSize, tpl.ptr(), (int)tpl.step, tplRoiSize, dst.ptr<Ipp32f>(), (int)dst.step, funCfg, buffer);
dst = cv::max(dst, 0); // handle edge case from rounding in variance computation which can result in negative values
return status >= 0;
}
static bool ipp_matchTemplate( Mat& img, Mat& templ, Mat& result, int method)
{
CV_INSTRUMENT_REGION_IPP();
if(img.channels() != 1)
return false;
// These functions are not efficient if template size is comparable with image size
if(templ.size().area()*4 > img.size().area())
return false;
// CV_8U SQDIFF/SQDIFF_NORMED suffer from float32 catastrophic cancellation
// in IPP's internal accumulators; fall through to the double-precision path instead.
if(img.depth() == CV_8U && (method == cv::TM_SQDIFF || method == cv::TM_SQDIFF_NORMED))
return false;
if(method == cv::TM_SQDIFF)
{
if(ipp_sqrDistance(img, templ, result))
return true;
}
else if(method == cv::TM_SQDIFF_NORMED)
{
if(ipp_crossCorr(img, templ, result, false))
{
common_matchTemplate(img, templ, result, cv::TM_SQDIFF_NORMED, 1);
return true;
}
}
else if(method == cv::TM_CCORR)
{
if(ipp_crossCorr(img, templ, result, false))
return true;
}
else if(method == cv::TM_CCORR_NORMED)
{
if(ipp_crossCorr(img, templ, result, true))
return true;
}
else if(method == cv::TM_CCOEFF || method == cv::TM_CCOEFF_NORMED)
{
if(ipp_crossCorr(img, templ, result, false))
{
common_matchTemplate(img, templ, result, method, 1);
return true;
}
}
return false;
}
}
#endif
////////////////////////////////////////////////////////////////////////////////////////////////////////
void cv::matchTemplate( InputArray _img, InputArray _templ, OutputArray _result, int method, InputArray _mask )
@@ -1196,7 +1067,22 @@ void cv::matchTemplate( InputArray _img, InputArray _templ, OutputArray _result,
_result.create(corrSize, CV_32F);
Mat result = _result.getMat();
CV_IPP_RUN_FAST(ipp_matchTemplate(img, templ, result, method))
{
int hal_res = cv_hal_matchTemplate(img.data, img.step, img.cols, img.rows,
templ.data, templ.step, templ.cols, templ.rows,
result.ptr<float>(), result.step, depth, cn, method);
if (hal_res == CV_HAL_ERROR_OK)
{
if (method == cv::TM_SQDIFF_NORMED || method == cv::TM_CCOEFF || method == cv::TM_CCOEFF_NORMED)
common_matchTemplate(img, templ, result, method, 1);
return;
}
else if (hal_res != CV_HAL_ERROR_NOT_IMPLEMENTED)
{
CV_Error_(cv::Error::StsInternal,
("HAL implementation matchTemplate ==> cv_hal_matchTemplate returned %d (0x%08x)", hal_res, hal_res));
}
}
bool use64f = (depth == CV_8U) && (method == cv::TM_SQDIFF || method == cv::TM_SQDIFF_NORMED);
Mat result64f;
-136
View File
@@ -193,57 +193,6 @@ thresh_8u( const Mat& _src, Mat& _dst, uchar thresh, uchar maxval, int type )
src_step = dst_step = roi.width;
}
#if defined(HAVE_IPP)
CV_IPP_CHECK()
{
IppiSize sz = { roi.width, roi.height };
CV_SUPPRESS_DEPRECATED_START
switch( type )
{
case THRESH_TRUNC:
if (_src.data == _dst.data && CV_INSTRUMENT_FUN_IPP(ippiThreshold_GT_8u_C1IR, _dst.ptr(), (int)dst_step, sz, thresh) >= 0)
{
CV_IMPL_ADD(CV_IMPL_IPP);
return;
}
if (CV_INSTRUMENT_FUN_IPP(ippiThreshold_GT_8u_C1R, _src.ptr(), (int)src_step, _dst.ptr(), (int)dst_step, sz, thresh) >= 0)
{
CV_IMPL_ADD(CV_IMPL_IPP);
return;
}
setIppErrorStatus();
break;
case THRESH_TOZERO:
if (_src.data == _dst.data && CV_INSTRUMENT_FUN_IPP(ippiThreshold_LTVal_8u_C1IR, _dst.ptr(), (int)dst_step, sz, thresh+1, 0) >= 0)
{
CV_IMPL_ADD(CV_IMPL_IPP);
return;
}
if (CV_INSTRUMENT_FUN_IPP(ippiThreshold_LTVal_8u_C1R, _src.ptr(), (int)src_step, _dst.ptr(), (int)dst_step, sz, thresh + 1, 0) >= 0)
{
CV_IMPL_ADD(CV_IMPL_IPP);
return;
}
setIppErrorStatus();
break;
case THRESH_TOZERO_INV:
if (_src.data == _dst.data && CV_INSTRUMENT_FUN_IPP(ippiThreshold_GTVal_8u_C1IR, _dst.ptr(), (int)dst_step, sz, thresh, 0) >= 0)
{
CV_IMPL_ADD(CV_IMPL_IPP);
return;
}
if (CV_INSTRUMENT_FUN_IPP(ippiThreshold_GTVal_8u_C1R, _src.ptr(), (int)src_step, _dst.ptr(), (int)dst_step, sz, thresh, 0) >= 0)
{
CV_IMPL_ADD(CV_IMPL_IPP);
return;
}
setIppErrorStatus();
break;
}
CV_SUPPRESS_DEPRECATED_END
}
#endif
int j = 0;
const uchar* src = _src.ptr();
uchar* dst = _dst.ptr();
@@ -577,57 +526,6 @@ thresh_16s( const Mat& _src, Mat& _dst, short thresh, short maxval, int type )
src_step = dst_step = roi.width;
}
#if defined(HAVE_IPP)
CV_IPP_CHECK()
{
IppiSize sz = { roi.width, roi.height };
CV_SUPPRESS_DEPRECATED_START
switch( type )
{
case THRESH_TRUNC:
if (_src.data == _dst.data && CV_INSTRUMENT_FUN_IPP(ippiThreshold_GT_16s_C1IR, dst, (int)dst_step*sizeof(dst[0]), sz, thresh) >= 0)
{
CV_IMPL_ADD(CV_IMPL_IPP);
return;
}
if (CV_INSTRUMENT_FUN_IPP(ippiThreshold_GT_16s_C1R, src, (int)src_step*sizeof(src[0]), dst, (int)dst_step*sizeof(dst[0]), sz, thresh) >= 0)
{
CV_IMPL_ADD(CV_IMPL_IPP);
return;
}
setIppErrorStatus();
break;
case THRESH_TOZERO:
if (_src.data == _dst.data && CV_INSTRUMENT_FUN_IPP(ippiThreshold_LTVal_16s_C1IR, dst, (int)dst_step*sizeof(dst[0]), sz, thresh + 1, 0) >= 0)
{
CV_IMPL_ADD(CV_IMPL_IPP);
return;
}
if (CV_INSTRUMENT_FUN_IPP(ippiThreshold_LTVal_16s_C1R, src, (int)src_step*sizeof(src[0]), dst, (int)dst_step*sizeof(dst[0]), sz, thresh + 1, 0) >= 0)
{
CV_IMPL_ADD(CV_IMPL_IPP);
return;
}
setIppErrorStatus();
break;
case THRESH_TOZERO_INV:
if (_src.data == _dst.data && CV_INSTRUMENT_FUN_IPP(ippiThreshold_GTVal_16s_C1IR, dst, (int)dst_step*sizeof(dst[0]), sz, thresh, 0) >= 0)
{
CV_IMPL_ADD(CV_IMPL_IPP);
return;
}
if (CV_INSTRUMENT_FUN_IPP(ippiThreshold_GTVal_16s_C1R, src, (int)src_step*sizeof(src[0]), dst, (int)dst_step*sizeof(dst[0]), sz, thresh, 0) >= 0)
{
CV_IMPL_ADD(CV_IMPL_IPP);
return;
}
setIppErrorStatus();
break;
}
CV_SUPPRESS_DEPRECATED_END
}
#endif
#if (CV_SIMD || CV_SIMD_SCALABLE)
int i, j;
v_int16 thresh8 = vx_setall_s16( thresh );
@@ -799,40 +697,6 @@ thresh_32f( const Mat& _src, Mat& _dst, float thresh, float maxval, int type )
roi.height = 1;
}
#if defined(HAVE_IPP)
CV_IPP_CHECK()
{
IppiSize sz = { roi.width, roi.height };
switch( type )
{
case THRESH_TRUNC:
if (0 <= CV_INSTRUMENT_FUN_IPP(ippiThreshold_GT_32f_C1R, src, (int)src_step*sizeof(src[0]), dst, (int)dst_step*sizeof(dst[0]), sz, thresh))
{
CV_IMPL_ADD(CV_IMPL_IPP);
return;
}
setIppErrorStatus();
break;
case THRESH_TOZERO:
if (0 <= CV_INSTRUMENT_FUN_IPP(ippiThreshold_LTVal_32f_C1R, src, (int)src_step*sizeof(src[0]), dst, (int)dst_step*sizeof(dst[0]), sz, nextafterf(thresh, std::numeric_limits<float>::infinity()), 0))
{
CV_IMPL_ADD(CV_IMPL_IPP);
return;
}
setIppErrorStatus();
break;
case THRESH_TOZERO_INV:
if (0 <= CV_INSTRUMENT_FUN_IPP(ippiThreshold_GTVal_32f_C1R, src, (int)src_step*sizeof(src[0]), dst, (int)dst_step*sizeof(dst[0]), sz, thresh, 0))
{
CV_IMPL_ADD(CV_IMPL_IPP);
return;
}
setIppErrorStatus();
break;
}
}
#endif
#if (CV_SIMD || CV_SIMD_SCALABLE)
int i, j;
v_float32 thresh4 = vx_setall_f32( thresh );