From fae6a60228df8cf3029982672d933dc3cc97d43c Mon Sep 17 00:00:00 2001 From: Jonathan Thomas Date: Fri, 13 Mar 2026 23:39:22 -0500 Subject: [PATCH] Prevent Tracker crashes by resetting optical-flow state when the video frame size changes between tracked frames. --- src/CVTracker.cpp | 18 ++++++++++++++++-- tests/CVTracker.cpp | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/src/CVTracker.cpp b/src/CVTracker.cpp index f243fcfb5..b719d383e 100644 --- a/src/CVTracker.cpp +++ b/src/CVTracker.cpp @@ -185,11 +185,25 @@ bool CVTracker::trackFrame(cv::Mat &frame, size_t frameId) cv::Mat gray; cv::cvtColor(frame, gray, cv::COLOR_BGR2GRAY); + const bool prevGrayMatches = + !prevGray.empty() && + prevGray.size() == gray.size() && + prevGray.type() == gray.type(); + const bool fullPrevGrayMatches = + !fullPrevGray.empty() && + fullPrevGray.size() == gray.size() && + fullPrevGray.type() == gray.type(); + + if (!prevGray.empty() && !prevGrayMatches) { + prevPts.clear(); + lostCount = 0; + } + cv::Rect2d cand; bool didKLT = false; // Try KLT-based drift - if (!prevGray.empty() && !prevPts.empty()) { + if (prevGrayMatches && !prevPts.empty()) { std::vector currPts; std::vector status; std::vector err; @@ -233,7 +247,7 @@ bool CVTracker::trackFrame(cv::Mat &frame, size_t frameId) if (!didKLT) { ++lostCount; cand = lastBox; - if (!fullPrevGray.empty()) { + if (fullPrevGrayMatches) { cv::Mat flow; cv::calcOpticalFlowFarneback( fullPrevGray, gray, flow, diff --git a/tests/CVTracker.cpp b/tests/CVTracker.cpp index 0ac1116c5..9336f74eb 100644 --- a/tests/CVTracker.cpp +++ b/tests/CVTracker.cpp @@ -144,6 +144,43 @@ TEST_CASE( "Track_BoundingBoxClipping", "[libopenshot][opencv][tracker]" ) CHECK(tracker_pc.GetError() == false); } +TEST_CASE( "Track_FrameSizeChangeDoesNotCrash", "[libopenshot][opencv][tracker]" ) +{ + std::string json_data = R"proto( + { + "tracker-type": "KCF", + "region": { + "normalized_x": 0.2, + "normalized_y": 0.2, + "normalized_width": 0.3, + "normalized_height": 0.3, + "first-frame": 1 + } + } )proto"; + + ProcessingController tracker_pc; + CVTracker tracker(json_data, tracker_pc); + + cv::Mat frame1(360, 640, CV_8UC3, cv::Scalar(0, 0, 0)); + cv::rectangle(frame1, cv::Rect(128, 72, 160, 108), cv::Scalar(255, 255, 255), cv::FILLED); + + cv::Mat frame2 = frame1.clone(); + + cv::Mat frame3(180, 320, CV_8UC3, cv::Scalar(0, 0, 0)); + cv::rectangle(frame3, cv::Rect(64, 36, 80, 54), cv::Scalar(255, 255, 255), cv::FILLED); + + REQUIRE_NOTHROW(tracker.initTracker(frame1, 1)); + REQUIRE_NOTHROW(tracker.trackFrame(frame2, 2)); + REQUIRE_NOTHROW(tracker.trackFrame(frame3, 3)); + + FrameData fd = tracker.GetTrackedData(3); + CHECK(fd.frame_id == 3); + CHECK(fd.x1 >= 0.0f); + CHECK(fd.y1 >= 0.0f); + CHECK(fd.x2 <= 1.0f); + CHECK(fd.y2 <= 1.0f); +} + TEST_CASE( "SaveLoad_Protobuf", "[libopenshot][opencv][tracker]" ) {