Алгоритм слежения за основными целями Проверка кода C++

1. Введение

Staple сочетает в себе алгоритм локального признака HOG и цветовую гистограмму глобального признака для отслеживания цели.

Во-первых, авторы обнаружили, что цветового распределения недостаточно, чтобы отличить цель от фона. Такие шаблоны, как локальные элементы, как правило, плохо работают при серьезных деформациях.

Автор проделал связанную работу по этим двум вопросам и пришел к следующим выводам.

  1. Сверточные фильтры неустойчивы к сильным деформациям.
  2. Онлайн-обучение может вызвать дрейф модели, то есть алгоритм использует прогноз в качестве положительной выборки для обучения и обновления модели. Если прогноз неверен, за ним последуют ошибки.
  3. Цветовая гистограмма не учитывает положение пикселя, что может в определенной степени уменьшить влияние деформации.
  4. Надежность корреляционного фильтра CF относительно высока, и он может играть роль, когда различие между целевым цветом и цветом фона недостаточно.

Поэтому авторы объединили их для отслеживания объектов.

2. Теоретические методы

2.1 Общий подход

pt = argmaxp ∈ S tf ( T ( xt , p ) ; θ t - 1 ) p_t = argmax_ {p {\ in} S_t} f (T (x_t, p); {\ theta} _ {t-1})пт"="а р г м а хр е Sтж ( Т ( хт,р ) ;ят - 1)

для ттt кадр, может пройти прямоугольникpt p_tптНа изображении xt x_tИкстВыберите цель в и максимизируйте значение функции подсчета очков.
( ффf — прямоугольное окноppФункция оценки p , функция оценкиTTT — преобразование изображения,θ \ thetaθ — параметр модели)

θ т знак равно argmin θ ∈ Q { L ( θ ; Икс т + λ р ( θ ) } \ theta_t = argmin _ {\ theta \ in Q} \ {L (\ theta; X_t + \ lambda R (\ theta) \};ят"="а р г м н _θ Q{ L ( θ ;Икст+λ р ( θ ) }

Икс т знак равно { ( xi , пи ) } я знак равно 1 т X_t = \ {(x_i, p_i) \} ^ t_ {я = 1}Икст"="{ ( хя,пя) }я = 1т

Можно взять набор θ \ тетаθ минимизирует общую функцию потерь.
(ЛЛL — функция, связанная с целевой позицией в предыдущем кадре,RRR - обычный термин)

2.2 Функция подсчета очков

ж ( Икс ) знак равно γ tmplftmpl ( Икс ) + γ histfhist ( Икс ) f (x) = {\ gamma} _ {tmpl} f_ {tmpl} (x) + {\ gamma} _ {hist} f_ {hist} ( Икс)ж ( х )"="ст м п лфт м п л( х )+спривет _ _ _фпривет _ _ _( х )

ftmpl ( Икс ; час ) знак равно ∑ ты ∈ τ час [ ты ] Т ϕ Икс [ ты ] f_ {tmpl} (x; h) = \ sum_ {u \ in {\ tau}} h [u] ^ T \ phi_x [у]фт м п л( х ;ч )"="и е тч [ ты ]Т фх[ ты ]

ϕ x : τ → RK \phi_x:\tau\rightarrow\mathbb{R}^Kфх:трK
τ : ⊂ Z 2 \ тау: \ подмножество \ mathbb {Z} ^ 2т:Z2

Функция f состоит из двух элементов: один — оценка шаблона, а второй — оценка гистограммы. Эта формула представляет, предполагая, что изображение x с Z 2 Z^2Z2 означает

3. Тезисы

Алгоритм отслеживания целей STAPLE сочетает в себе два метода функции HOG и цветовой гистограммы. Поскольку функция HOG более устойчива к размытию в движении и освещенности, но неустойчива к деформации, соответствующая цветовая гистограмма очень устойчива к деформации и неустойчива к изменениям освещенности. Таким образом, два метода могут дополнять друг друга, поэтому два метода используются одновременно и делятся на два канала обработки.

Алгоритм указывает цель с помощью прямоугольной рамки в первом кадре, затем отслеживает незнакомый объект на видео и остается устойчивым к изменениям его внешнего вида. Поскольку внешний вид объекта может сильно различаться в зависимости от видео, неэффективно оценивать другие кадры только по модели, вычисленной с использованием первого кадра, и обычной практикой является обновление модели прогнозами на основе отслеживаемых кадров в качестве обучающих данных. При поиске целевого местоположения в каждом кадре изображения рассмотрите возможность поиска сначала в каждом повороте изображения, а затем в масштабировании.

4. Тестирование кода

Автор статьи реализует этот алгоритм с помощью MATLAB. И я использую версию, реализованную на C++ великим богом xuduo35 на Github , Оригинальная ссылка на проект Github выглядит следующим образом:

Исходный код бумаги (MATLAB):
https://github.com/bertinetto/staple
xuduo35 (C++):
https://github.com/xuduo35/STAPLE

Эта статья относится к коду xuduo34 и вызывает файлы fhog.cpp, fhog.h, sse.hpp, staple_tracker.cpp, staple_tracker.hppв этом проекте, и ниже приводится только код основной функции.

int main(int argc, char * argv[]){
    
    
    // 数据定义
    STAPLE_TRACKER staple;  //创建staple跟踪对象
    std::vector<cv::Rect_<float>> result_rects;     //创建矩形容器,存储所有算法识别出的跟踪框
    cv::VideoCapture capture(0);	//创建VideoCapture类
    cv::Mat image;      //用来存储每一帧
    cv::Mat tempImage;  //每一帧的临时变量
    int64 tic, toc;     //算法运行时间起始点与终止点
    double time = 0;
    bool show_visualization = true;
    bool first_image = true;

    // 设置鼠标操作回调函数
    cv::namedWindow("STAPLE");
    cv::setMouseCallback("STAPLE", on_MouseHandle, (void*)&image);

    while(1){
    
    
        capture.read(image);	//逐帧读取视频
        flip(image, image, 1);	//将读取的视频左右反转
        if (image.empty()) {
    
    	//如果视频结束或未检测到摄像头则跳出循环
            break;
        }

        if(drawing_finished == false){
    
    
            // 鼠标按下drawing_box=true,在视频画面frame上画矩形
            if( drawing_box ){
    
    
                tempImage.copyTo(image);
                cv::rectangle(image,groundtruth_rect.tl(),groundtruth_rect.br(),cv::Scalar(0,0,255));// 画框
            }
            else{
    
    
                image.copyTo(tempImage);//拷贝源图到临时变量
            }
        }
        else{
    
    
            // 如果是第一帧图像,则进行staple初始化操作,反之则只更新staple
            if (first_image){
    
    
                // staple初始化操作
                staple.tracker_staple_initialize(image, groundtruth_rect);
                // staple目标追踪
                staple.tracker_staple_train(image, true);
                first_image = false;
            } else{
    
    
                groundtruth_rect = staple.tracker_staple_update(image);
                staple.tracker_staple_train(image, false);
            }
        }
        // 可视化部分
        if (show_visualization) {
    
    
            // 显示算法识别的跟踪框
            cv::rectangle(image, groundtruth_rect, cv::Scalar(0, 128, 255), 2);

            // 写入测试视频
            // ******************** //
            // video.write(image);
            // ******************** //

            // 输出图像显示结果
            cv::imshow("STAPLE", image);
            std::cout << "Center: [" << groundtruth_rect.tl().x +groundtruth_rect.width/2 << ", " << groundtruth_rect.tl().y + groundtruth_rect.height/2 << "]" << std::endl;

            char key = cv::waitKey(10);
            if (key == 27 || key == 'q' || key == 'Q')
                break;
        }


    }
    cv::destroyAllWindows();

}


/******************** 函数定义 ********************/
// 使轴对齐
cv::Rect_<float> getAxisAlignedBB(std::vector<cv::Point2f> polygon)
{
    
    
    double cx = double(polygon[0].x + polygon[1].x + polygon[2].x + polygon[3].x) / 4.;
    double cy = double(polygon[0].y + polygon[1].y + polygon[2].y + polygon[3].y) / 4.;
    double x1 = std::min(std::min(std::min(polygon[0].x, polygon[1].x), polygon[2].x), polygon[3].x);
    double x2 = std::max(std::max(std::max(polygon[0].x, polygon[1].x), polygon[2].x), polygon[3].x);
    double y1 = std::min(std::min(std::min(polygon[0].y, polygon[1].y), polygon[2].y), polygon[3].y);
    double y2 = std::max(std::max(std::max(polygon[0].y, polygon[1].y), polygon[2].y), polygon[3].y);
    double A1 = norm(polygon[1] - polygon[2])*norm(polygon[2] - polygon[3]);
    double A2 = (x2 - x1) * (y2 - y1);
    double s = sqrt(A1 / A2);
    double w = s * (x2 - x1) + 1;
    double h = s * (y2 - y1) + 1;
    cv::Rect_<float> rect(cx-1-w/2.0, cy-1-h/2.0, w, h);
    return rect;

}
// 获取groundtruth内的矩形坐标
std::vector<cv::Rect_<float>> getgroundtruth(std::string txt_file)
{
    
    
    std::vector<cv::Rect_<float>> rects;
    std::ifstream gt;
    gt.open(txt_file.c_str());
    if (!gt.is_open())
        std::cout << "Ground truth file " << txt_file
                  << " can not be read" << std::endl;
    std::string line;
    float x1, y1, x2, y2, x3, y3, x4, y4;
    while (getline(gt, line)) {
    
    
        std::replace(line.begin(), line.end(), ',', ' ');
        std::stringstream ss;
        ss.str(line);
        ss >> x1 >> y1 >> x2 >> y2 >> x3 >> y3 >> x4 >> y4;
        std::vector<cv::Point2f>polygon;
        polygon.push_back(cv::Point2f(x1, y1));
        polygon.push_back(cv::Point2f(x2, y2));
        polygon.push_back(cv::Point2f(x3, y3));
        polygon.push_back(cv::Point2f(x4, y4));
        rects.push_back(getAxisAlignedBB(polygon)); //0-index
    }
    gt.close();
    return rects;
}
// 第一帧画框鼠标响应
void on_MouseHandle(int event, int x, int y, int flags, void* param ){
    
    
    cv::Mat& image = *(cv::Mat*) param;
    switch( event)
    {
    
    
        //鼠标移动消息
        case cv::EVENT_MOUSEMOVE:
        {
    
    
            if( drawing_box )//如果是否进行绘制的标识符为真,则记录下长和宽到RECT型变量中
            {
    
    
                groundtruth_rect.width = x-groundtruth_rect.x;
                groundtruth_rect.height = y-groundtruth_rect.y;
            }
        }
            break;

            //左键按下消息
        case cv::EVENT_LBUTTONDOWN:
        {
    
    
            drawing_box = true;
            groundtruth_rect = cv::Rect( x, y, 0, 0 );//记录起始点
        }
            break;

            //左键抬起消息
        case cv::EVENT_LBUTTONUP:
        {
    
    
            drawing_box = false;//置标识符为false
            drawing_finished = true;
            //对宽和高小于0的处理
            if( groundtruth_rect.width < 0 )
            {
    
    
                groundtruth_rect.x += groundtruth_rect.width;
                groundtruth_rect.width *= -1;
            }

            if( groundtruth_rect.height < 0 )
            {
    
    
                groundtruth_rect.y += groundtruth_rect.height;
                groundtruth_rect.height *= -1;
            }
            //调用函数进行绘制
            cv::rectangle(image,groundtruth_rect.tl(),groundtruth_rect.br(),cv::Scalar(0,0,255));// 画框
        }
            break;
    }
}

На картинке ниже представлена ​​тестовая программа, адаптированная из программы слежения за целью Staple и объединенная с картой глубины камеры Realsense D435i.

Поскольку полный код не выпущен, вы можете изменить его на основе кода версии xuduo C++ в соответствии со своими потребностями.

Этот пост был впервые опубликован в моем личном блоге: https://www.mahaofei.com/ , добро пожаловать в гости.

Guess you like

Origin blog.csdn.net/weixin_44543463/article/details/125625022
C++