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

Merge branch 4.x

This commit is contained in:
Alexander Smorkalov
2026-02-11 13:54:39 +03:00
committed by Alexander Smorkalov
468 changed files with 16647 additions and 11284 deletions
+19 -5
View File
@@ -162,26 +162,40 @@ approxPolyDP_( const Point_<T>* src_contour, int count0, Point_<T>* dst_contour,
if( pos != slice.end )
{
double dx, dy, dist, max_dist = 0;
double dx, dy, max_dist_2_mul_segment_len_2 = 0;
dx = end_pt.x - start_pt.x;
dy = end_pt.y - start_pt.y;
double segment_len_2 = dx * dx + dy * dy;
CV_Assert( dx != 0 || dy != 0 );
while( pos != slice.end )
{
READ_PT(pt, pos);
dist = fabs((pt.y - start_pt.y) * dx - (pt.x - start_pt.x) * dy);
double projection = ((pt.x - start_pt.x) * dx + (pt.y - start_pt.y) * dy);
if( dist > max_dist )
double dist_2_mul_segment_len_2;
if ( projection < 0 )
{
max_dist = dist;
dist_2_mul_segment_len_2 = ((pt.x - start_pt.x) * (pt.x - start_pt.x) + (pt.y - start_pt.y) * (pt.y - start_pt.y)) * segment_len_2;
} else if ( projection > segment_len_2 )
{
dist_2_mul_segment_len_2 = ((pt.x - end_pt.x) * (pt.x - end_pt.x) + (pt.y - end_pt.y) * (pt.y - end_pt.y)) * segment_len_2;
} else
{
double dist = ((pt.y - start_pt.y) * dx - (pt.x - start_pt.x) * dy);
dist_2_mul_segment_len_2 = dist * dist;
}
if( dist_2_mul_segment_len_2 > max_dist_2_mul_segment_len_2 )
{
max_dist_2_mul_segment_len_2 = dist_2_mul_segment_len_2;
right_slice.start = (pos+count-1)%count;
}
}
le_eps = max_dist * max_dist <= eps * (dx * dx + dy * dy);
le_eps = max_dist_2_mul_segment_len_2 <= eps * segment_len_2;
}
else
{
@@ -321,7 +321,7 @@ bilateralFilter_32f( const Mat& src, Mat& dst, int d,
}
// parallel_for usage
CV_CPU_DISPATCH(bilateralFilterInvoker_32f, (cn, radius, maxk, space_ofs, temp, dst, scale_index, space_weight, expLUT),
CV_CPU_DISPATCH(bilateralFilterInvoker_32f, (cn, radius, maxk, space_ofs, temp, dst, scale_index, space_weight, expLUT, kExpNumBins),
CV_CPU_DISPATCH_MODES_ALL);
}
+15 -14
View File
@@ -58,7 +58,7 @@ void bilateralFilterInvoker_8u(
int* space_ofs, float *space_weight, float *color_weight);
void bilateralFilterInvoker_32f(
int cn, int radius, int maxk, int *space_ofs,
const Mat& temp, Mat& dst, float scale_index, float *space_weight, float *expLUT);
const Mat& temp, Mat& dst, float scale_index, float *space_weight, float *expLUT, int kExpNumBins);
#ifndef CV_CPU_OPTIMIZATION_DECLARATIONS_ONLY
@@ -495,9 +495,9 @@ class BilateralFilter_32f_Invoker :
public:
BilateralFilter_32f_Invoker(int _cn, int _radius, int _maxk, int *_space_ofs,
const Mat& _temp, Mat& _dest, float _scale_index, float *_space_weight, float *_expLUT) :
const Mat& _temp, Mat& _dest, float _scale_index, float *_space_weight, float *_expLUT, int _kExpNumBins) :
cn(_cn), radius(_radius), maxk(_maxk), space_ofs(_space_ofs),
temp(&_temp), dest(&_dest), scale_index(_scale_index), space_weight(_space_weight), expLUT(_expLUT)
temp(&_temp), dest(&_dest), scale_index(_scale_index), space_weight(_space_weight), expLUT(_expLUT), kExpNumBins(_kExpNumBins)
{
}
@@ -550,7 +550,7 @@ public:
v_float32 val0 = vx_load(ksptr);
v_float32 knan0 = v_not_nan(val0);
v_float32 alpha0 = v_and(v_and(v_mul(v_absdiff(val0, rval0), sindex), v_not_nan(rval0)), knan0);
v_int32 idx0 = v_trunc(alpha0);
v_int32 idx0 = v_min(v_trunc(alpha0), vx_setall_s32(kExpNumBins));
alpha0 = v_sub(alpha0, v_cvt_f32(idx0));
v_float32 w0 = v_and(v_mul(kweight, v_muladd(v_lut(this->expLUT + 1, idx0), alpha0, v_mul(v_lut(this->expLUT, idx0), v_sub(v_one, alpha0)))), knan0);
v_wsum0 = v_add(v_wsum0, w0);
@@ -560,7 +560,7 @@ public:
v_float32 val1 = vx_load(ksptr + nlanes);
v_float32 knan1 = v_not_nan(val1);
v_float32 alpha1 = v_and(v_and(v_mul(v_absdiff(val1, rval1), sindex), v_not_nan(rval1)), knan1);
v_int32 idx1 = v_trunc(alpha1);
v_int32 idx1 = v_min(v_trunc(alpha1), vx_setall_s32(kExpNumBins));
alpha1 = v_sub(alpha1, v_cvt_f32(idx1));
v_float32 w1 = v_and(v_mul(kweight, v_muladd(v_lut(this->expLUT + 1, idx1), alpha1, v_mul(v_lut(this->expLUT, idx1), v_sub(v_one, alpha1)))), knan1);
v_wsum1 = v_add(v_wsum1, w1);
@@ -570,7 +570,7 @@ public:
v_float32 val2 = vx_load(ksptr + nlanes_2);
v_float32 knan2 = v_not_nan(val2);
v_float32 alpha2 = v_and(v_and(v_mul(v_absdiff(val2, rval2), sindex), v_not_nan(rval2)), knan2);
v_int32 idx2 = v_trunc(alpha2);
v_int32 idx2 = v_min(v_trunc(alpha2), vx_setall_s32(kExpNumBins));
alpha2 = v_sub(alpha2, v_cvt_f32(idx2));
v_float32 w2 = v_and(v_mul(kweight, v_muladd(v_lut(this->expLUT + 1, idx2), alpha2, v_mul(v_lut(this->expLUT, idx2), v_sub(v_one, alpha2)))), knan2);
v_wsum2 = v_add(v_wsum2, w2);
@@ -580,7 +580,7 @@ public:
v_float32 val3 = vx_load(ksptr + nlanes_3);
v_float32 knan3 = v_not_nan(val3);
v_float32 alpha3 = v_and(v_and(v_mul(v_absdiff(val3, rval3), sindex), v_not_nan(rval3)), knan3);
v_int32 idx3 = v_trunc(alpha3);
v_int32 idx3 = v_min(v_trunc(alpha3), vx_setall_s32(kExpNumBins));
alpha3 = v_sub(alpha3, v_cvt_f32(idx3));
v_float32 w3 = v_and(v_mul(kweight, v_muladd(v_lut(this->expLUT + 1, idx3), alpha3, v_mul(v_lut(this->expLUT, idx3), v_sub(v_one, alpha3)))), knan3);
v_wsum3 = v_add(v_wsum3, w3);
@@ -611,7 +611,7 @@ public:
v_float32 val0 = vx_load(ksptr);
v_float32 knan0 = v_not_nan(val0);
v_float32 alpha0 = v_and(v_and(v_mul(v_absdiff(val0, rval0), sindex), rval0_not_nan), knan0);
v_int32 idx0 = v_trunc(alpha0);
v_int32 idx0 = v_min(v_trunc(alpha0), vx_setall_s32(kExpNumBins));
alpha0 = v_sub(alpha0, v_cvt_f32(idx0));
v_float32 w0 = v_and(v_mul(kweight, v_muladd(v_lut(this->expLUT + 1, idx0), alpha0, v_mul(v_lut(this->expLUT, idx0), v_sub(v_one, alpha0)))), knan0);
v_wsum0 = v_add(v_wsum0, w0);
@@ -621,7 +621,7 @@ public:
v_float32 val1 = vx_load(ksptr + nlanes);
v_float32 knan1 = v_not_nan(val1);
v_float32 alpha1 = v_and(v_and(v_mul(v_absdiff(val1, rval1), sindex), rval1_not_nan), knan1);
v_int32 idx1 = v_trunc(alpha1);
v_int32 idx1 = v_min(v_trunc(alpha1), vx_setall_s32(kExpNumBins));
alpha1 = v_sub(alpha1, v_cvt_f32(idx1));
v_float32 w1 = v_and(v_mul(kweight, v_muladd(v_lut(this->expLUT + 1, idx1), alpha1, v_mul(v_lut(this->expLUT, idx1), v_sub(v_one, alpha1)))), knan1);
v_wsum1 = v_add(v_wsum1, w1);
@@ -640,7 +640,7 @@ public:
{
const float* ksptr = sptr_j + space_ofs[k];
float val = *ksptr;
float alpha = std::abs(val - rval) * scale_index;
float alpha = std::min(std::abs(val - rval) * scale_index, (float)kExpNumBins);
int idx = cvFloor(alpha);
alpha -= idx;
if (!cvIsNaN(val))
@@ -681,7 +681,7 @@ public:
v_float32 knan = v_and(v_and(v_not_nan(kb), v_not_nan(kg)), v_not_nan(kr));
v_float32 alpha = v_and(v_and(v_and(v_and(v_mul(v_add(v_add(v_absdiff(kb, rb), v_absdiff(kg, rg)), v_absdiff(kr, rr)), sindex), v_not_nan(rb)), v_not_nan(rg)), v_not_nan(rr)), knan);
v_int32 idx = v_trunc(alpha);
v_int32 idx = v_min(v_trunc(alpha), vx_setall_s32(kExpNumBins));
alpha = v_sub(alpha, v_cvt_f32(idx));
v_float32 w = v_and(v_mul(kweight, v_muladd(v_lut(this->expLUT + 1, idx), alpha, v_mul(v_lut(this->expLUT, idx), v_sub(v_one, alpha)))), knan);
@@ -709,7 +709,7 @@ public:
bool v_NAN = cvIsNaN(b) || cvIsNaN(g) || cvIsNaN(r);
float rb = rsptr[0], rg = rsptr[1], rr = rsptr[2];
bool r_NAN = cvIsNaN(rb) || cvIsNaN(rg) || cvIsNaN(rr);
float alpha = (std::abs(b - rb) + std::abs(g - rg) + std::abs(r - rr)) * scale_index;
float alpha = std::min((std::abs(b - rb) + std::abs(g - rg) + std::abs(r - rr)) * scale_index, (float)kExpNumBins);
int idx = cvFloor(alpha);
alpha -= idx;
if (!v_NAN)
@@ -753,17 +753,18 @@ private:
const Mat* temp;
Mat *dest;
float scale_index, *space_weight, *expLUT;
int kExpNumBins;
};
} // namespace anon
void bilateralFilterInvoker_32f(
int cn, int radius, int maxk, int *space_ofs,
const Mat& temp, Mat& dst, float scale_index, float *space_weight, float *expLUT)
const Mat& temp, Mat& dst, float scale_index, float *space_weight, float *expLUT, int kExpNumBins)
{
CV_INSTRUMENT_REGION();
BilateralFilter_32f_Invoker body(cn, radius, maxk, space_ofs, temp, dst, scale_index, space_weight, expLUT);
BilateralFilter_32f_Invoker body(cn, radius, maxk, space_ofs, temp, dst, scale_index, space_weight, expLUT, kExpNumBins);
parallel_for_(Range(0, dst.rows), body, dst.total()/(double)(1<<16));
}
+38 -4
View File
@@ -219,9 +219,9 @@ void convexHull( InputArray _points, OutputArray _hull, bool clockwise, bool ret
}
for( i = 0; i < tl_count-1; i++ )
hullbuf[nout++] = int(pointer[tl_stack[i]] - data0);
hullbuf[nout++] = tl_stack[i];
for( i = tr_count - 1; i > 0; i-- )
hullbuf[nout++] = int(pointer[tr_stack[i]] - data0);
hullbuf[nout++] = tr_stack[i];
int stop_idx = tr_count > 2 ? tr_stack[1] : tl_count > 2 ? tl_stack[tl_count - 2] : -1;
// lower half
@@ -257,9 +257,43 @@ void convexHull( InputArray _points, OutputArray _hull, bool clockwise, bool ret
}
for( i = 0; i < bl_count-1; i++ )
hullbuf[nout++] = int(pointer[bl_stack[i]] - data0);
hullbuf[nout++] = bl_stack[i];
for( i = br_count-1; i > 0; i-- )
hullbuf[nout++] = int(pointer[br_stack[i]] - data0);
hullbuf[nout++] = br_stack[i];
if (!returnPoints)
{
// Try keep monotonous indices in case of self-intersection.
for (i = 0; i < nout; ++i)
{
auto prev = pointer[hullbuf[(i == 0 ? nout : i) - 1]];
auto next = pointer[hullbuf[(i + 1) % nout]];
auto cur = pointer[hullbuf[i]];
if ((prev < cur && cur < next) || (prev > cur && cur > next))
{
continue;
}
for (int j = hullbuf[i] + 1; j < total; ++j)
{
cur = pointer[j];
if (*pointer[hullbuf[i]] == *cur)
{
if ((prev < cur && cur < next) || (prev > cur && cur > next))
{
hullbuf[i] = j;
break;
}
}
else
break;
}
}
}
for (i = 0; i < nout; ++i)
{
hullbuf[i] = int(pointer[hullbuf[i]] - data0);
}
// try to make the convex hull indices form
// an ascending or descending sequence by the cyclic
+1 -1
View File
@@ -1668,7 +1668,7 @@ ThickLine( Mat& img, Point2l p0, Point2l p1, const void* color,
{
if( line_type < cv::LINE_AA )
{
if( line_type == 1 || line_type == 4 || shift == 0 )
if( line_type == 1 || line_type == 8 || shift == 0 )
{
p0.x = (p0.x + (XY_ONE>>1)) >> XY_SHIFT;
p0.y = (p0.y + (XY_ONE>>1)) >> XY_SHIFT;
+33 -2
View File
@@ -1171,8 +1171,24 @@ static bool replacementFilter2D(int stype, int dtype, int kernel_type,
int anchor_x, int anchor_y,
double delta, int borderType, bool isSubmatrix)
{
// Prioritize stateless implementation
int res = cv_hal_filter_stateless(src_data, src_step, stype,
dst_data, dst_step, dtype, width, height,
full_width, full_height, offset_x, offset_y,
kernel_data, kernel_step, kernel_type,
kernel_width, kernel_height, anchor_x, anchor_y,
delta, borderType, isSubmatrix, src_data == dst_data);
if (res == CV_HAL_ERROR_OK)
{
return true;
} else if (res != CV_HAL_ERROR_NOT_IMPLEMENTED)
{
CV_Error_(cv::Error::StsInternal,
("HAL implementation filter_stateless ==> " CVAUX_STR(cv_hal_filter_stateless) " returned %d (0x%08x)", res, res));
}
cvhalFilter2D* ctx;
int res = cv_hal_filterInit(&ctx, kernel_data, kernel_step, kernel_type, kernel_width, kernel_height, width, height,
res = cv_hal_filterInit(&ctx, kernel_data, kernel_step, kernel_type, kernel_width, kernel_height, width, height,
stype, dtype, borderType, delta, anchor_x, anchor_y, isSubmatrix, src_data == dst_data);
if (res == CV_HAL_ERROR_NOT_IMPLEMENTED)
{
@@ -1385,8 +1401,23 @@ static bool replacementSepFilter(int stype, int dtype, int ktype,
uchar * kernely_data, int kernely_len,
int anchor_x, int anchor_y, double delta, int borderType)
{
// Prioritize stateless implementation
int res = cv_hal_sepFilter_stateless(src_data, src_step, stype,
dst_data, dst_step, dtype,
width, height, full_width, full_height, offset_x, offset_y,
kernelx_data, kernelx_len, kernely_data, kernely_len, ktype,
anchor_x, anchor_y, delta, borderType);
if (res == CV_HAL_ERROR_OK)
{
return true;
} else if (res != CV_HAL_ERROR_NOT_IMPLEMENTED)
{
CV_Error_(cv::Error::StsInternal,
("HAL implementation sepFilter_stateless ==> " CVAUX_STR(cv_hal_sepFilter_stateless) " returned %d (0x%08x)", res, res));
}
cvhalFilter2D *ctx;
int res = cv_hal_sepFilterInit(&ctx, stype, dtype, ktype,
res = cv_hal_sepFilterInit(&ctx, stype, dtype, ktype,
kernelx_data, kernelx_len,
kernely_data, kernely_len,
anchor_x, anchor_y, delta, borderType);
+112
View File
@@ -86,6 +86,40 @@ int my_hal_filterFree(cvhalFilter2D *context) {
*/
struct cvhalFilter2D {};
/**
@brief 2D filtering in a stateless manner
@param src_data source image data
@param src_step source image step
@param src_type source image type
@param dst_data destination image data
@param dst_step destination image step
@param dst_type destination image type
@param width images width
@param height images height
@param full_width full width of source image (outside the ROI)
@param full_height full height of source image (outside the ROI)
@param offset_x source image ROI offset X
@param offset_y source image ROI offset Y
@param kernel_data pointer to kernel data
@param kernel_step kernel step
@param kernel_type kernel type (CV_8U, ...)
@param kernel_width kernel width
@param kernel_height kernel height
@param anchor_x relative X position of center point within the kernel
@param anchor_y relative Y position of center point within the kernel
@param delta added to pixel values
@param borderType border processing mode (CV_HAL_BORDER_REFLECT, ...)
@param isSubmatrix indicates whether the submatrices will be allowed as source image
@param allowInplace indicates whether the inplace operation will be possible
@sa cv::filter2D, cv::hal::Filter2D
*/
inline int hal_ni_filter_stateless(const uchar * src_data, size_t src_step, int src_type,
uchar * dst_data, size_t dst_step, int dst_type,
int width, int height, int full_width, int full_height, int offset_x, int offset_y,
const uchar * kernel_data, size_t kernel_step, int kernel_type, int kernel_width, int kernel_height,
int anchor_x, int anchor_y, double delta, int borderType, bool isSubmatrix, bool allowInplace)
{ return CV_HAL_ERROR_NOT_IMPLEMENTED; }
/**
@brief hal_filterInit
@param context double pointer to user-defined context
@@ -131,11 +165,45 @@ inline int hal_ni_filter(cvhalFilter2D *context, uchar *src_data, size_t src_ste
inline int hal_ni_filterFree(cvhalFilter2D *context) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
//! @cond IGNORED
#define cv_hal_filter_stateless hal_ni_filter_stateless
#define cv_hal_filterInit hal_ni_filterInit
#define cv_hal_filter hal_ni_filter
#define cv_hal_filterFree hal_ni_filterFree
//! @endcond
/**
@brief separable filtering in a stateless manner
@param src_data source image data
@param src_step source image step
@param src_type source image type
@param dst_data destination image data
@param dst_step destination image step
@param dst_type destination image type
@param width images width
@param height images height
@param full_width full width of source image (outside the ROI)
@param full_height full height of source image (outside the ROI)
@param offset_x source image ROI offset X
@param offset_y source image ROI offset Y
@param kernelx_data pointer to x-kernel data
@param kernelx_len x-kernel vector length
@param kernely_data pointer to y-kernel data
@param kernely_len y-kernel vector length
@param kernel_type kernel type (CV_8U, ...)
@param anchor_x relative X position of center point within the kernel
@param anchor_y relative Y position of center point within the kernel
@param delta added to pixel values
@param borderType border processing mode (CV_HAL_BORDER_REFLECT, ...)
@sa cv::sepFilter2D, cv::hal::SepFilter2D
*/
inline int hal_ni_sepFilter_stateless(const uchar * src_data, size_t src_step, int src_type,
uchar * dst_data, size_t dst_step, int dst_type,
int width, int height, int full_width, int full_height, int offset_x, int offset_y,
const uchar * kernelx_data, int kernelx_len,
const uchar * kernely_data, int kernely_len,
int kernel_type, int anchor_x, int anchor_y, double delta, int borderType)
{ return CV_HAL_ERROR_NOT_IMPLEMENTED; }
/**
@brief hal_sepFilterInit
@param context double pointer to user-defined context
@@ -177,11 +245,54 @@ inline int hal_ni_sepFilter(cvhalFilter2D *context, uchar *src_data, size_t src_
inline int hal_ni_sepFilterFree(cvhalFilter2D *context) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
//! @cond IGNORED
#define cv_hal_sepFilter_stateless hal_ni_sepFilter_stateless
#define cv_hal_sepFilterInit hal_ni_sepFilterInit
#define cv_hal_sepFilter hal_ni_sepFilter
#define cv_hal_sepFilterFree hal_ni_sepFilterFree
//! @endcond
/**
@brief morphology in a stateless manner
@param operation morphology operation CV_HAL_MORPH_ERODE or CV_HAL_MORPH_DILATE
@param src_data source image data
@param src_step source image step
@param src_type source image type
@param dst_data destination image data
@param dst_step destination image step
@param dst_type destination image type
@param width images width
@param height images height
@param src_full_width full width of source image (outside the ROI)
@param src_full_height full height of source image (outside the ROI)
@param src_roi_x source image ROI X offset
@param src_roi_y source image ROI Y offset
@param dst_full_width full width of destination image
@param dst_full_height full height of destination image
@param dst_roi_x destination image ROI X offset
@param dst_roi_y destination image ROI Y offset
@param kernel_data pointer to kernel data
@param kernel_step kernel step
@param kernel_type kernel type (CV_8U, ...)
@param kernel_width kernel width
@param kernel_height kernel height
@param anchor_x relative X position of center point within the kernel
@param anchor_y relative Y position of center point within the kernel
@param borderType border processing mode (CV_HAL_BORDER_REFLECT, ...)
@param borderValue values to use for CV_HAL_BORDER_CONSTANT mode
@param iterations number of iterations
@param allowSubmatrix indicates whether the submatrices will be allowed as source image
@param allowInplace indicates whether the inplace operation will be possible
@sa cv::erode, cv::dilate, cv::morphologyEx, cv::hal::Morph
*/
inline int hal_ni_morph_stateless(int operation, const uchar * src_data, size_t src_step, int src_type,
uchar * dst_data, size_t dst_step, int dst_type,
int width, int height, int src_full_width, int src_full_height, int src_roi_x, int src_roi_y,
int dst_full_width, int dst_full_height, int dst_roi_x, int dst_roi_y,
const uchar * kernel_data, size_t kernel_step, int kernel_type, int kernel_width, int kernel_height,
int anchor_x, int anchor_y, int borderType, const double borderValue[4],
int iterations, bool allowSubmatrix, bool allowInplace)
{ return CV_HAL_ERROR_NOT_IMPLEMENTED; }
/**
@brief hal_morphInit
@param context double pointer to user-defined context
@@ -233,6 +344,7 @@ inline int hal_ni_morph(cvhalFilter2D *context, uchar *src_data, size_t src_step
inline int hal_ni_morphFree(cvhalFilter2D *context) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
//! @cond IGNORED
#define cv_hal_morph_stateless hal_ni_morph_stateless
#define cv_hal_morphInit hal_ni_morphInit
#define cv_hal_morph hal_ni_morph
#define cv_hal_morphFree hal_ni_morphFree
+9 -9
View File
@@ -1024,7 +1024,7 @@ void HoughLinesPointSet( InputArray _point, OutputArray _lines, int lines_max, i
int r = idx - (n+1)*(numrho+2) - 1;
line.rho = static_cast<float>(min_rho) + r * (float)rho_step;
line.angle = static_cast<float>(min_theta) + n * (float)theta_step;
lines.push_back(Vec3d((double)accum[idx], (double)line.rho, (double)line.angle));
lines.emplace_back((double)accum[idx], (double)line.rho, (double)line.angle);
}
Mat(lines).copyTo(_lines);
@@ -1125,7 +1125,7 @@ public:
{
if (ptr[x])
{
list.push_back(Point(x, y));
list.emplace_back(x, y);
}
}
}
@@ -1489,7 +1489,7 @@ protected:
// Check if the circle has enough support
if(maxCount > accThreshold)
{
circlesLocal.push_back(EstimatedCircle(Vec3f(curCenter.x, curCenter.y, rBest), maxCount));
circlesLocal.emplace_back(Vec3f(curCenter.x, curCenter.y, rBest), maxCount);
}
}
@@ -1847,7 +1847,7 @@ static void HoughCirclesAlt( const Mat& img, std::vector<EstimatedCircle>& circl
continue;
mdata[y*mstep + x] = (uchar)1;
stack.push_back(Point(x, y));
stack.emplace_back(x, y);
bool backtrace_mode = false;
do
@@ -1858,7 +1858,7 @@ static void HoughCirclesAlt( const Mat& img, std::vector<EstimatedCircle>& circl
int vy = dyData[p.y*dxystep + p.x];
float mag = std::sqrt((float)vx*vx+(float)vy*vy);
nz.push_back(Vec4f((float)p.x, (float)p.y, (float)vx, (float)vy));
nz.emplace_back((float)p.x, (float)p.y, (float)vx, (float)vy);
CV_Assert(mdata[p.y*mstep + p.x] == 1);
int sx = cvRound(vx * RAY_FP_SCALE / mag);
@@ -1903,7 +1903,7 @@ static void HoughCirclesAlt( const Mat& img, std::vector<EstimatedCircle>& circl
if( mdata[y_*mstep + x_] || !edgeData[y_*estep + x_])
continue;
mdata[y_*mstep + x_] = (uchar)1;
stack.push_back(Point(x_, y_));
stack.emplace_back(x_, y_);
neighbors++;
}
@@ -1919,7 +1919,7 @@ static void HoughCirclesAlt( const Mat& img, std::vector<EstimatedCircle>& circl
// insert a special "stop marker" in the end of each
// connected component to make sure we
// finalize and analyze the arc segment
nz.push_back(Vec4f(0.f, 0.f, 0.f, 0.f));
nz.emplace_back(0.f, 0.f, 0.f, 0.f);
}
}
@@ -1951,7 +1951,7 @@ static void HoughCirclesAlt( const Mat& img, std::vector<EstimatedCircle>& circl
{
float cx = (float)((left + x - 1)*dp*0.5f);
float cy = (float)(y*dp);
centers.push_back(Point2f(cx, cy));
centers.emplace_back(cx, cy);
left = -1;
}
}
@@ -2223,7 +2223,7 @@ static void HoughCirclesAlt( const Mat& img, std::vector<EstimatedCircle>& circl
// (accepted ? '+' : '-'), cx, cy, rk, cjk.weight, count, max_runlen, cjk.mask);
if( accepted )
local_circles.push_back(EstimatedCircle(Vec3f(cx, cy, (float)rk), cjk.weight));
local_circles.emplace_back(Vec3f(cx, cy, (float)rk), cjk.weight);
}
}
}
+15 -1
View File
@@ -212,8 +212,22 @@ static bool halMorph(int op, int src_type, int dst_type,
int kernel_width, int kernel_height, int anchor_x, int anchor_y,
int borderType, const double borderValue[4], int iterations, bool isSubmatrix)
{
// Prioritize stateless implementation
int res = cv_hal_morph_stateless(op, src_data, src_step, src_type, dst_data, dst_step, dst_type, width, height,
roi_width, roi_height, roi_x, roi_y, roi_width2, roi_height2, roi_x2, roi_y2,
kernel_data, kernel_step, kernel_type, kernel_width, kernel_height, anchor_x, anchor_y,
borderType, borderValue, iterations, isSubmatrix, src_data == dst_data);
if (res == CV_HAL_ERROR_OK)
{
return true;
} else if (res != CV_HAL_ERROR_NOT_IMPLEMENTED)
{
CV_Error_(cv::Error::StsInternal,
("HAL implementation morph_stateless ==> " CVAUX_STR(cv_hal_morph_stateless) " returned %d (0x%08x)", res, res));
}
cvhalFilter2D * ctx;
int res = cv_hal_morphInit(&ctx, op, src_type, dst_type, width, height,
res = cv_hal_morphInit(&ctx, op, src_type, dst_type, width, height,
kernel_type, kernel_data, kernel_step, kernel_width, kernel_height,
anchor_x, anchor_y,
borderType, borderValue,
+191
View File
@@ -0,0 +1,191 @@
#include "precomp.hpp"
#include <cmath>
namespace {
template <typename T>
void calculateCrossPowerSpectrum(const cv::Mat& dft1, const cv::Mat& dft2, cv::Mat& cps)
{
for (int row = 0; row < dft1.rows; ++row)
{
auto* cpsp = cps.ptr<cv::Vec<T, 2>>(row);
const auto* dft1p = dft1.ptr<cv::Vec<T, 2>>(row);
const auto* dft2p = dft2.ptr<cv::Vec<T, 2>>(row);
for (int col = 0; col < dft1.cols; ++col)
{
const T re = dft1p[col][0] * dft2p[col][0] + dft1p[col][1] * dft2p[col][1];
const T im = dft1p[col][0] * dft2p[col][1] - dft1p[col][1] * dft2p[col][0];
const T mag = std::sqrt(re * re + im * im);
cpsp[col][0] = re / mag;
cpsp[col][1] = im / mag;
}
}
}
cv::Mat calculateCrossPowerSpectrum(const cv::Mat& dft1, const cv::Mat& dft2)
{
cv::Mat cps(dft1.rows, dft1.cols, dft1.type());
if (dft1.type() == CV_32FC2)
calculateCrossPowerSpectrum<float>(dft1, dft2, cps);
else if (dft1.type() == CV_64FC2)
calculateCrossPowerSpectrum<double>(dft1, dft2, cps);
else
CV_Error(cv::Error::StsNotImplemented, "Only CV_32FC2 and CV_64FC2 types are supported");
return cps;
}
void fftshift(cv::Mat& out)
{
int cx = out.cols / 2;
int cy = out.rows / 2;
cv::Mat q0(out, cv::Rect(0, 0, cx, cy));
cv::Mat q1(out, cv::Rect(cx, 0, cx, cy));
cv::Mat q2(out, cv::Rect(0, cy, cx, cy));
cv::Mat q3(out, cv::Rect(cx, cy, cx, cy));
cv::Mat tmp;
q0.copyTo(tmp);
q3.copyTo(q0);
tmp.copyTo(q3);
q1.copyTo(tmp);
q2.copyTo(q1);
tmp.copyTo(q2);
}
bool isOutOfBounds(const cv::Point2i& peak, const cv::Mat& mat, int size)
{
return peak.x - size / 2 < 0 || peak.y - size / 2 < 0 || peak.x + size / 2 >= mat.cols ||
peak.y + size / 2 >= mat.rows;
}
bool reduceL2size(int& L2size)
{
L2size -= 2;
return L2size >= 3;
}
int getL1size(int L2Usize, double L1ratio)
{
int L1size = static_cast<int>(std::floor(L1ratio * L2Usize));
return (L1size % 2) ? L1size : L1size + 1;
}
cv::Point2d getPeakSubpixel(const cv::Mat& mat)
{
const auto m = moments(mat);
return cv::Point2d(m.m10 / m.m00, m.m01 / m.m00);
}
bool accuracyReached(const cv::Point2d& L1peak, const cv::Point2d& L1mid)
{
return std::abs(L1peak.x - L1mid.x) < 0.5 && std::abs(L1peak.y - L1mid.y) < 0.5;
}
cv::Point2d getSubpixelShift(const cv::Mat& L3,
const cv::Point2d& L3peak,
const cv::Point2d& L3mid,
int L2size)
{
while (isOutOfBounds(L3peak, L3, L2size))
if (!reduceL2size(L2size))
return L3peak - L3mid;
cv::Mat L2 = L3(cv::Rect(static_cast<int>(L3peak.x - L2size / 2),
static_cast<int>(L3peak.y - L2size / 2),
L2size,
L2size));
cv::Point2d L2peak = getPeakSubpixel(L2);
cv::Point2d L2mid(L2.cols / 2, L2.rows / 2);
return L3peak - L3mid + L2peak - L2mid;
}
} // namespace
cv::Point2d
cv::phaseCorrelateIterative(InputArray _src1, InputArray _src2, int L2size, int maxIters)
{
CV_INSTRUMENT_REGION();
Mat src1 = _src1.getMat();
Mat src2 = _src2.getMat();
CV_Assert(src1.type() == src2.type());
CV_Assert(src1.size() == src2.size());
CV_Assert(src1.type() == CV_32FC1 || src1.type() == CV_64FC1);
// apply DFT window to input images
Mat window;
createHanningWindow(window, src1.size(), _src1.type());
Mat image1, image2;
multiply(_src1, window, image1);
multiply(_src2, window, image2);
// compute the DFTs of input images
dft(image1, image1, DFT_COMPLEX_OUTPUT);
dft(image2, image2, DFT_COMPLEX_OUTPUT);
// compute the phase correlation landscape L3
Mat L3 = calculateCrossPowerSpectrum(image1, image2);
dft(L3, L3, DFT_INVERSE | DFT_SCALE | DFT_REAL_OUTPUT);
fftshift(L3);
Point2d L3mid(L3.cols / 2, L3.rows / 2);
// calculate the maximum correlation location
Point2i L3peak;
minMaxLoc(L3, nullptr, nullptr, nullptr, &L3peak);
// reduce the L2size as long as L2 is out of bounds of L3
while (isOutOfBounds(L3peak, L3, L2size))
if (!reduceL2size(L2size))
return Point2d(L3peak) - L3mid;
// extract the L2 maximum correlation neighborhood from L3
Mat L2 = L3(Rect(L3peak.x - L2size / 2, L3peak.y - L2size / 2, L2size, L2size));
// upsample L2 maximum correlation neighborhood to get L2U
Mat L2U;
const int L2Usize = 223; // empirically determined optimal constant
resize(L2, L2U, {L2Usize, L2Usize}, 0, 0, INTER_LINEAR);
const Point2d L2Umid(L2U.cols / 2, L2U.rows / 2);
// run the iterative refinement algorithm using the specified L1 ratio
// gradually decrease L1 ratio if convergence is not achieved
const double L1ratioBase = 0.45; // empirically determined optimal constant
const double L1ratioStep = 0.025;
for (double L1ratio = L1ratioBase; getL1size(L2U.cols, L1ratio) > 0; L1ratio -= L1ratioStep)
{
Point2d L2Upeak = L2Umid; // reset the accumulated L2U peak position
const int L1size = getL1size(L2U.cols, L1ratio); // calculate the current L1 size
const Point2d L1mid(L1size / 2, L1size / 2); // update the L1 mid position
// perform the iterative refinement algorithm
for (int iter = 0; iter < maxIters; ++iter)
{
// verify that the L1 region is within the L2U region
if (isOutOfBounds(L2Upeak, L2U, L1size))
break;
// extract the L1 region from L2U
const Mat L1 = L2U(Rect(static_cast<int>(L2Upeak.x - L1size / 2),
static_cast<int>(L2Upeak.y - L1size / 2),
L1size,
L1size));
// calculate the centroid location
const Point2d L1peak = getPeakSubpixel(L1);
// add the contribution of the current iteration to the accumulated L2U peak location
L2Upeak += Point2d(std::round(L1peak.x - L1mid.x), std::round(L1peak.y - L1mid.y));
// check for convergence
if (accuracyReached(L1peak, L1mid))
// return the refined subpixel image shift
return Point2d(L3peak) - L3mid +
(L2Upeak - L2Umid + L1peak - L1mid) /
(static_cast<double>(L2Usize) / L2size);
}
}
// iterative refinement failed to converge, return non-iterative subpixel shift
return getSubpixelShift(L3, Point2d(L3peak), L3mid, L2size);
}
+5 -5
View File
@@ -365,7 +365,7 @@ cv::RotatedRect cv::minAreaRect( InputArray _points )
Mat hull;
Point2f out[3];
RotatedRect box;
box.angle = -(float)CV_PI / 2; // default angle for box without rotation and single point
double angle = -CV_PI / 2; // default angle for box without rotation and single point
static const bool clockwise = false;
convexHull(_points, hull, clockwise, true);
@@ -390,7 +390,7 @@ cv::RotatedRect cv::minAreaRect( InputArray _points )
if (out[1].x == 0.f && out[1].y > 0.f)
std::swap(box.size.width, box.size.height);
else
box.angle += (float)atan2( (double)out[1].y, (double)out[1].x );
angle = -atan2( (double)out[1].x, (double)out[1].y );
}
else if( n == 2 )
{
@@ -406,12 +406,12 @@ cv::RotatedRect cv::minAreaRect( InputArray _points )
}
else if (dy < 0)
{
box.angle = (float)atan2( dy, dx );
angle = atan2( dy, dx );
std::swap(box.size.width, box.size.height);
}
else if (dy > 0)
{
box.angle += (float)atan2( dy, dx );
angle = -atan2( dx, dy );
}
}
else
@@ -420,7 +420,7 @@ cv::RotatedRect cv::minAreaRect( InputArray _points )
box.center = hpoints[0];
}
box.angle = (float)(box.angle*180/CV_PI);
box.angle = (float)(angle*180/CV_PI);
CV_DbgCheckGE(box.angle, -90.0f, "");
CV_DbgCheckLT(box.angle, 0.0f, "");
return box;
+9 -3
View File
@@ -41,6 +41,7 @@ OTHER DEALINGS IN THE SOFTWARE.
#include "opencv2/core/hal/intrin.hpp"
#include <iostream>
#include <algorithm>
using namespace std;
@@ -1199,12 +1200,17 @@ void stackBlur(InputArray _src, OutputArray _dst, Size ksize)
CV_Assert( ksize.width > 0 && ksize.width % 2 == 1 &&
ksize.height > 0 && ksize.height % 2 == 1 );
int radiusH = ksize.height / 2;
int radiusW = ksize.width / 2;
int stype = _src.type(), sdepth = _src.depth();
Mat src = _src.getMat();
if (ksize.width > src.cols)
ksize.width = (src.cols % 2 == 0) ? std::max(1, src.cols - 1) : src.cols;
if (ksize.height > src.rows)
ksize.height = (src.rows % 2 == 0) ? std::max(1, src.rows - 1) : src.rows;
int radiusH = ksize.height / 2;
int radiusW = ksize.width / 2;
if (ksize.width == 1)
{
_src.copyTo(_dst);
+7 -7
View File
@@ -265,7 +265,7 @@ int Subdiv2D::newPoint(Point2f pt, bool isvirtual, int firstEdge)
{
if( freePoint == 0 )
{
vtx.push_back(Vertex());
vtx.emplace_back();
freePoint = (int)(vtx.size()-1);
}
int vidx = freePoint;
@@ -520,8 +520,8 @@ void Subdiv2D::initDelaunay( Rect rect )
Point2f ppB( rx, ry + big_coord );
Point2f ppC( rx - big_coord, ry - big_coord );
vtx.push_back(Vertex());
qedges.push_back(QuadEdge());
vtx.emplace_back();
qedges.emplace_back();
freeQEdge = 0;
freePoint = 0;
@@ -566,8 +566,8 @@ void Subdiv2D::initDelaunay( Rect2f rect )
Point2f ppB( rx, ry + big_coord );
Point2f ppC( rx - big_coord, ry - big_coord );
vtx.push_back(Vertex());
qedges.push_back(QuadEdge());
vtx.emplace_back();
qedges.emplace_back();
freeQEdge = 0;
freePoint = 0;
@@ -784,7 +784,7 @@ void Subdiv2D::getEdgeList(std::vector<Vec4f>& edgeList) const
{
Point2f org = vtx[qedges[i].pt[0]].pt;
Point2f dst = vtx[qedges[i].pt[2]].pt;
edgeList.push_back(Vec4f(org.x, org.y, dst.x, dst.y));
edgeList.emplace_back(org.x, org.y, dst.x, dst.y);
}
}
}
@@ -836,7 +836,7 @@ void Subdiv2D::getTriangleList(std::vector<Vec6f>& triangleList) const
edgemask[edge_a] = true;
edgemask[edge_b] = true;
edgemask[edge_c] = true;
triangleList.push_back(Vec6f(a.x, a.y, b.x, b.y, c.x, c.y));
triangleList.emplace_back(a.x, a.y, b.x, b.y, c.x, c.y);
}
}