From 67ede46c6513d6bca02e92820df34e943ea357d6 Mon Sep 17 00:00:00 2001 From: Shiven Solanki Date: Thu, 8 Oct 2026 19:13:57 +0800 Subject: [PATCH] Merge pull request #30168 from sshivensolanki:fix-trackervit-scalefactor video: fix TrackerVit input scalefactor computed as Scalar - #30168 Fixes #30164 ### Problem `TrackerVitImpl` computes the input normalisation as i2bp.scalefactor = (1.0 / parameters.stdvalue) * (1 / 255.0); `operator/(double, Scalar)` is the quaternion inverse (`conj(b) * a / |b|^2`), not an elementwise reciprocal. With the default `stdvalue = (0.229, 0.224, 0.225)` the applied scalefactor is `(0.00586, -0.00573, -0.00576)` instead of `(0.01712, 0.01751, 0.01743)`: channels 1 and 2 are sign-flipped and all three are about 1/3 of the intended magnitude. This was introduced in 4.11 when the elementwise `(dst - mean) / std` was replaced with `Image2BlobParams`. ### Fix Compute `1 / (255 * std)` per channel in a small helper used by both constructors. A zero std entry (the unused 4th channel by default) maps to 0. ### Tests `vittrack.accuracy_vittrack` on the `tracking/bag` sequence, measured locally on macOS ARM64 (4.x and 5.x): | | min IoU | mean IoU | |---|---|---| | before | 0.642 | 0.757 | | after | 0.682 | 0.776 | On other CI platforms (x64, Windows, no-HAL) the minimum IoU with the fix is 0.658, so the existing 0.64 threshold is kept. ### 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 --- modules/video/src/tracking/tracker_vit.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/modules/video/src/tracking/tracker_vit.cpp b/modules/video/src/tracking/tracker_vit.cpp index 7335b76b19..34ec430d03 100644 --- a/modules/video/src/tracking/tracker_vit.cpp +++ b/modules/video/src/tracking/tracker_vit.cpp @@ -38,6 +38,15 @@ TrackerVit::Params::Params() #ifdef HAVE_OPENCV_DNN +// Per-channel 1/(255*std). Note: (1.0 / Scalar) is the quaternion inverse, not an elementwise reciprocal +static Scalar getScaleFactor(const Scalar& stdvalue) +{ + Scalar scalefactor; + for (int i = 0; i < 4; i++) + scalefactor[i] = stdvalue[i] != 0 ? 1.0 / (stdvalue[i] * 255.0) : 0.0; + return scalefactor; +} + class TrackerVitImpl : public TrackerVit { public: @@ -50,7 +59,7 @@ public: net.setPreferableTarget(parameters.target); i2bp.mean = parameters.meanvalue * 255.0; - i2bp.scalefactor = (1.0 / parameters.stdvalue) * (1 / 255.0); + i2bp.scalefactor = getScaleFactor(parameters.stdvalue); tracking_score_threshold = parameters.tracking_score_threshold; } @@ -60,7 +69,7 @@ public: net = model; i2bp.mean = meanvalue * 255.0; - i2bp.scalefactor = (1.0 / stdvalue) * (1 / 255.0); + i2bp.scalefactor = getScaleFactor(stdvalue); tracking_score_threshold = _tracking_score_threshold; }