【问题标题】:OpenCV Kalman Filter, erasing from std::vectorOpenCV 卡尔曼滤波器,从 std::vector 中擦除
【发布时间】:2014-09-22 21:47:42
【问题描述】:

我有这个问题,看看。

我正在使用 OpenCV 来跟踪视频中的手。使用 CascadeDetector 定位手,然后使用 CamSHIFT 进行跟踪。如果 CamShift 算法在某些帧失败,我还使用卡尔曼滤波器来校正手的位置。

当我试图从存储手的 std::vector 中删除一个元素时,问题就出现了。删除的原因是由于某些问题,人脸被误解为手,所以我正在检测人脸,如果手区域与人脸区域相交,我会删除那只手。我知道,很天真,但我目前还处于起步阶段。 代码如下所示:

class Hand {
...
public:
    struct 
    {
        ...
        struct {
            cv::Mat_<float> measurement;
            cv::KalmanFilter KF;
            cv::Mat state;
            cv::Mat processNoise;
        } KalmanTracker;
    } Tracker;
};
...
std::vector<Hand> hands;
...
std::vector<cv::Rect> faces;
faceCascade.detectMultiScale(frame, faces, 1.1, 2, CV_HAAR_FIND_BIGGEST_OBJECT);
// iterate through hands
for (std::vector<Hand>::iterator it = hands.begin(); it != hands.end(); ++it) {
    // iterate through faces:
    for (std::vector<cv::Rect>::iterator fc = faces.begin(); fc != faces.end(); ++fc) {
        cv::Rect intersection = (*it).handBox.boundingRect() & (*fc);
        // check if they have at leasy 75% intersection
        if (intersection.area() >= ((*it).handBox.boundingRect().area() * 0.75)) {
            // delete that hand from list
            hands.erase(it);    // this gets me a a EXC_BAD_ACCESS
        }
    }
}

hands.erase(it) 行在指向我的KalmanFilterTracker 结构时为我提供了一个EXC_BAD_ACCESS,以及mat.hpp 中的这一行与EXC_i386_GPFLT

inline void Mat::release()
{
    if( refcount && CV_XADD(refcount, -1) == 1 ) // EXC_BAD_ACCESS, code=EXC_i386_GPFLT
    ...
}

handsfaces 都不是空的。 如果我从我的项目中完全删除卡尔曼滤波器并提及或使用它,错误就会消失。

【问题讨论】:

  • 从向量中擦除后不能重用旧的迭代器。

标签: c++ opencv exc-bad-access kalman-filter


【解决方案1】:

vector::erase(iterator) 使被擦除的迭代器无效。但它确实返回了一个新的迭代器,指向向量中的下一个有效项。因此该行应该是:

it = hands.erase(it);

在 berak 发表评论后编辑:

啊,我错过了内循环。由于您在内部循环中使it 无效,因此事情变得有些复杂。您需要跳过一些障碍才能做到正确。

for (std::vector<Hand>::iterator it = hands.begin(); it != hands.end(); ) {
    bool found = false;
    // iterate through faces:
    for (std::vector<cv::Rect>::iterator fc = faces.begin(); fc != faces.end() && !found; ++fc) {
        cv::Rect intersection = (*it).handBox.boundingRect() & (*fc);
        // check if they have at leasy 75% intersection
        if (intersection.area() >= ((*it).handBox.boundingRect().area() * 0.75)) {
            found = true;
        }
    }

    if (found) {
        it = hands.erase(it);
    }
    else {
        ++it;
    }
}

可以将一些迭代器操作折叠到内部循环中,但将其保留在外部会使代码更清晰,更容易推理。

【讨论】:

  • 更改了行,但错误仍然存​​在。我怀疑错误与迭代器本身无关,而与卡尔曼滤波器实例有关。
  • @Gnagn,不幸的是它没有那么简单。因为它在内部循环中,所以需要另一个 it != hands.end();之后检查(如果向量的最后一项被删除,it==end() 现在)
  • 但是这样在if (found) 语句中它是一个有效的迭代器,然后在下一个循环之前你再次增加它。你错过了一个这样做,还是我错了?
  • @Jepessen,哎呀。现在好些了吗?
  • 我认为是的。我之所以这么说是因为它可能与错误有关,考虑到我不太了解错误是什么...... :(
【解决方案2】:

好的,通过一些调试我发现,我的手向量有时会变空,并且在尝试从空向量中擦除时出现错误。 剩下的就是找出为什么它会变空以及在什么时候变空。 谢谢大家。

【讨论】:

    猜你喜欢
    • 2011-04-14
    • 2017-08-11
    • 2012-05-14
    • 1970-01-01
    • 2013-08-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-07-11
    相关资源
    最近更新 更多