mirror of
https://github.com/opencv/opencv.git
synced 2026-09-11 04:43:22 -05:00
Merge pull request #29762 from lazerg:fix/issue-29761-sgbm-3way-uniqueness-div-by-zero
calib3d: fix division by zero in SGBM 3-way mode when uniquenessRatio is 100 - #29762 Fixes #29761. `SGBM3WayMainLoop` derives its uniqueness threshold in the SIMD path as `(100*min_cost)/(100-uniquenessRatio)`, so a `uniquenessRatio` of 100 divides by zero and the process dies with SIGFPE. The scalar fallback right below it, and the other SGBM modes, express the same test as `cost*(100 - uniquenessRatio) < min_cost*100`, which needs no division and copes with the value fine. `MODE_HH4` goes through `CalcHorizontalSums`, which never divides, so only `MODE_SGBM_3WAY` reproduces. The SIMD shortcut is now skipped once `uniquenessRatio` reaches 100 and the scalar loop decides on its own, which is exactly what a build without SIMD already does. Ratios below 100 keep the fast path and produce identical output. The diff looks long because the existing block is indented one level, `?w=1` shows the real change. The second commit fixes the neighbouring case: `thresh` grows to `100*min_cost` as the ratio approaches 100, well past `SHRT_MAX`, and `(short)(thresh+1)` wraps. On the reporter's image pair at ratio 99, 3-way marked 48723 pixels valid while `MODE_SGBM`, `MODE_HH` and `MODE_HH4` all landed near 48370; saturating brings it to 48371. Verified with opencv_extra test data: `Calib3d_StereoSGBM.regression`, `Calib3d_StereoSGBM.deterministic`, `Calib3d_StereoSGBM_HH4.regression` and `Calib3d_StereoBM.regression` still pass. The new `Calib3d_StereoSGBM.regression_29761` aborts on unpatched 4.x under `-fsanitize=integer-divide-by-zero` and passes with the fix. The same code sits at `modules/stereo/src/stereosgbm.cpp` on 5.x, which is the path the reporter cited. The module move means the merge will not apply cleanly, so tell me if you would rather have a separate 5.x PR. ### Pull Request Readiness Checklist See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request - [x] I agree to contribute to the project under Apache 2 License. - [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV - [x] The PR is proposed to the proper branch - [x] There is a reference to the original bug report and related work - [x] There is accuracy test, performance test and test data in opencv_extra repository, if applicable Patch to opencv_extra has the same branch name. - [ ] The feature is well documented and sample code can be built with the project CMake
This commit is contained in:
committed by
GitHub
parent
d223a5ba93
commit
b2efa6f860
@@ -2074,41 +2074,44 @@ void SGBM3WayMainLoop::impl(const Range& range) const
|
||||
{
|
||||
d = 0;
|
||||
#if (CV_SIMD || CV_SIMD_SCALABLE)
|
||||
horPassCostVolume+=x;
|
||||
int thresh = (100*min_cost)/(100-uniquenessRatio);
|
||||
v_int16 thresh_reg = vx_setall_s16((short)(thresh+1));
|
||||
v_int16 d1 = vx_setall_s16((short)(best_d-1));
|
||||
v_int16 d2 = vx_setall_s16((short)(best_d+1));
|
||||
v_int16 eight_reg = vx_setall_s16((short)VTraits<v_int16>::vlanes());
|
||||
v_int16 cur_d = vx_load(idx_row);
|
||||
v_int16 mask;
|
||||
if(uniquenessRatio<100)
|
||||
{
|
||||
horPassCostVolume+=x;
|
||||
int thresh = (100*min_cost)/(100-uniquenessRatio);
|
||||
v_int16 thresh_reg = vx_setall_s16(saturate_cast<short>(thresh+1));
|
||||
v_int16 d1 = vx_setall_s16((short)(best_d-1));
|
||||
v_int16 d2 = vx_setall_s16((short)(best_d+1));
|
||||
v_int16 eight_reg = vx_setall_s16((short)VTraits<v_int16>::vlanes());
|
||||
v_int16 cur_d = vx_load(idx_row);
|
||||
v_int16 mask;
|
||||
|
||||
for( ; d <= D - 2*VTraits<v_int16>::vlanes(); d+=2*VTraits<v_int16>::vlanes() )
|
||||
{
|
||||
mask = v_and(v_lt(vx_load_aligned(horPassCostVolume + d), thresh_reg), v_or(v_lt(cur_d, d1), v_gt(cur_d, d2)));
|
||||
cur_d = v_add(cur_d, eight_reg);
|
||||
if( v_check_any(mask) )
|
||||
break;
|
||||
mask = v_and(v_lt(vx_load_aligned(horPassCostVolume + d + VTraits<v_int16>::vlanes()), thresh_reg), v_or(v_lt(cur_d, d1), v_gt(cur_d, d2)));
|
||||
cur_d = v_add(cur_d, eight_reg);
|
||||
if( v_check_any(mask) )
|
||||
break;
|
||||
}
|
||||
if( d <= D - 2*VTraits<v_int16>::vlanes() )
|
||||
{
|
||||
horPassCostVolume-=x;
|
||||
continue;
|
||||
}
|
||||
if( d <= D - VTraits<v_int16>::vlanes() )
|
||||
{
|
||||
if( v_check_any(v_and(v_lt(vx_load_aligned(horPassCostVolume + d), thresh_reg), v_or(v_lt(cur_d, d1), v_gt(cur_d, d2)))) )
|
||||
for( ; d <= D - 2*VTraits<v_int16>::vlanes(); d+=2*VTraits<v_int16>::vlanes() )
|
||||
{
|
||||
mask = v_and(v_lt(vx_load_aligned(horPassCostVolume + d), thresh_reg), v_or(v_lt(cur_d, d1), v_gt(cur_d, d2)));
|
||||
cur_d = v_add(cur_d, eight_reg);
|
||||
if( v_check_any(mask) )
|
||||
break;
|
||||
mask = v_and(v_lt(vx_load_aligned(horPassCostVolume + d + VTraits<v_int16>::vlanes()), thresh_reg), v_or(v_lt(cur_d, d1), v_gt(cur_d, d2)));
|
||||
cur_d = v_add(cur_d, eight_reg);
|
||||
if( v_check_any(mask) )
|
||||
break;
|
||||
}
|
||||
if( d <= D - 2*VTraits<v_int16>::vlanes() )
|
||||
{
|
||||
horPassCostVolume-=x;
|
||||
continue;
|
||||
}
|
||||
d+=VTraits<v_int16>::vlanes();
|
||||
if( d <= D - VTraits<v_int16>::vlanes() )
|
||||
{
|
||||
if( v_check_any(v_and(v_lt(vx_load_aligned(horPassCostVolume + d), thresh_reg), v_or(v_lt(cur_d, d1), v_gt(cur_d, d2)))) )
|
||||
{
|
||||
horPassCostVolume-=x;
|
||||
continue;
|
||||
}
|
||||
d+=VTraits<v_int16>::vlanes();
|
||||
}
|
||||
horPassCostVolume-=x;
|
||||
}
|
||||
horPassCostVolume-=x;
|
||||
#endif
|
||||
for( ; d < D; d++ )
|
||||
{
|
||||
|
||||
@@ -952,6 +952,18 @@ TEST(Calib3d_StereoSGBM, deterministic) {
|
||||
|
||||
}
|
||||
|
||||
TEST(Calib3d_StereoSGBM, regression_29761)
|
||||
{
|
||||
Mat leftImg(256, 256, CV_8UC1), rightImg(256, 256, CV_8UC1);
|
||||
randu(leftImg, Scalar(0), Scalar(255));
|
||||
randu(rightImg, Scalar(0), Scalar(255));
|
||||
|
||||
Ptr<StereoSGBM> sgbm = StereoSGBM::create( 0, 64, 5, 100, 200, 1, 31, 100, 0, 0, StereoSGBM::MODE_SGBM_3WAY);
|
||||
Mat leftDisp;
|
||||
sgbm->compute( leftImg, rightImg, leftDisp);
|
||||
EXPECT_EQ(countNonZero(leftDisp != -StereoMatcher::DISP_SCALE), 0);
|
||||
}
|
||||
|
||||
TEST(Calib3d_StereoSGBM_HH4, regression)
|
||||
{
|
||||
String path = cvtest::TS::ptr()->get_data_path() + "cv/stereomatching/datasets/teddy/";
|
||||
|
||||
Reference in New Issue
Block a user