Используйте Kalman Filter для фильтрации шума без задержки opencv c ++ - PullRequest
0 голосов
/ 26 апреля 2018

Моя задача - обнаружить оранжевый шарик на видео.Я обнаружил пороговое изображение на цветовом пространстве HSV и ограничительной рамке.Тогда у меня есть центр и радиус шара, с единицей измерения - пиксель.

Когда шар неподвижен, я ожидаю, что центр и радиус тоже будут статичны, но в действительности он имеет шум.Я использую Kalman Filter для фильтрации шума, и он работает хорошо.Но это задержка в режиме реального времени.Я пытаюсь оптимизировать параметры ковариации, но не работаю.

Так может ли кто-нибудь помочь мне static центр и радиус, когда шар неподвижен и без задержки?

1 Ответ

0 голосов
/ 26 апреля 2018

Вы уверены, что задержка вызвана ведьмой Калмана?В противном случае вы можете попробовать этот ленивый фильтр, только шумоподавляющий, но невероятно быстрый.Однако я подозреваю, что это преобразование HSV.

class noiseFilter
{
private:
    cv::Point2f ptLast;
    float ptMaxTol;
public:
    noiseFilter(float maxTol = 1.5f)
    {
        ptMaxTol = maxTol * maxTol;             // we do the pow(2) here so we don't have to do a square root on every update
        ptLast = cv::Point2f(0.0f, 0.0f);
    }
    cv::Point2f update(cv::Point2f &ptNew)      // update filter with new found point
    {
        float dist = pDistance2(ptLast, ptNew);
        if (dist > ptMaxTol) ptLast = ptNew;    // update only if distance is more than threshold
        return ptLast;
    }
    cv::Point2f getResult()                     // get result of filter
    {
        return ptLast;
    }
private:
    // calculate distance between 2 point without doing a sqrt
    float pDistance2(cv::Point2f &p1, cv::Point2f &p2)
    {
        float dx = p1.x - p2.x;
        float dy = p1.y - p2.y;
        return (dx * dx + dy * dy);
    }
};

int main()
{
    cv::Point2f pt;
    noiseFilter filter(2.1f);           // initialize filter wit max 2.1 pixels noise rejection.
    int x = 100, y = 120;

    for (int i = 0; i < 100; i++)
    {
        // generate some noise with 2 pixels variation
        pt.x = ((rand() % 200) - 100) * 0.01f + x;
        pt.y = ((rand() % 200) - 100) * 0.01f + y;

        cv::Point2f pts = filter.update(pt);
        printf("input x=%6.2f y=%6.2f  output x=%6.2f y=%6.2f\r\n", pt.x, pt.y, pts.x, pts.y);

        // do som random big update on random intervals
        if ((rand() % 50) == 1) {
            x += 15;
            printf("big update on X\r\n");
        }
        if ((rand() % 50) == 1){
            y += 25;
            printf("big update on Y\r\n");
        }

    }
    return 0;
}

Ниже шумового фильтра со сглаживанием.Работает на медленно и быстро движущихся объектах.

class noiseFilterSmooth
{
private:
    static const int maxHist = 10;
    cv::Point2f ptLast;
    float ptMaxTol;
    cv::Point2f hist[maxHist];
    int histHead,histSize;
public:
    noiseFilterSmooth(float maxTol = 1.5f)
    {
        histHead = histSize = 0;
        ptMaxTol = maxTol * maxTol;             // we do the pow(2) here so we don't have to do a square root on every update
        ptLast = cv::Point2f(0.0f, 0.0f);
    }
    cv::Point2f& update(cv::Point2f &ptNew)     // update filter with new found point
    {
        float dist = pDistance2(ptLast, ptNew);
        if (dist > ptMaxTol)  histSize = histHead = 0;      // reset smoothing filter if distance is more than threshold
        // update smoothing filter with last result
        hist[histHead] = ptNew;                 // update smoothing filter with last 
        histHead = (histHead + 1) % maxHist;
        if (histSize < maxHist) histSize++;
        return getResult();
    }
    cv::Point2f& getResult()                        // get result of filter
    {
        float sumx = 0, sumy = 0;
        for (int i = 0; i < histSize; i++)
        {
            sumx += hist[i].x;
            sumy += hist[i].y;
        }
        ptLast.x = sumx / histSize;
        ptLast.y = sumy / histSize;
        return ptLast;
    }
private:
    // calculate distance between 2 point without doing a sqrt
    float pDistance2(cv::Point2f &p1, cv::Point2f &p2)
    {
        float dx = p1.x - p2.x;
        float dy = p1.y - p2.y;
        return (dx * dx + dy * dy);
    }
};
...