Производительность calcOpticalFlowPyrLK хуже при высоких FPS

Я использую cv :: calcOpticalFlowPyrLK для расчета оптического потока от одного кадра к другому в видеопоследовательности. Я заметил, что отслеживание менее точное при высоких fps по сравнению с низким fps.

Исходная частота кадров составляет 30 кадров в секунду, и я обнаружил, что если я уменьшу частоту на 8, отслеживание будет намного более точным, чем использование всех кадров.

Размер фрейма — 360 * 480, а размер окна поиска — 21 * 21.

Любая помощь приветствуется!

0

Решение

основной cpp

#include <iostream>
#include <queue>
#include <opencv2/opencv.hpp>
#include "corner_tracker.h"using namespace std;
using namespace cv;

int main(int argc, char** argv) {
if (argc != 2) {
cout << "usage: " << argv[0] << " <video path>" << endl;
exit(1);
}
int frame_lag = 4;
string video_filepath(argv[1]);
VideoCapture vidcap(video_filepath);
Mat ref_frame, curr_frame, prev_frame;
queue<Mat> frame_buffer;
vector<Point2f> tracked_corners;
vector<Point2f> optical_flow;
CornerTrackerParameterBlock param;
CornerTracker corner_tracker(param);
Mat mask;
while (true){
vidcap >> ref_frame;
if (ref_frame.empty()) break;
cvtColor(ref_frame, curr_frame, CV_BGR2GRAY);

Mat tmp_frame;
curr_frame.copyTo(tmp_frame);
frame_buffer.push(tmp_frame);
if ((int)frame_buffer.size() < frame_lag+1 ) {
continue;
}
prev_frame = frame_buffer.front();
frame_buffer.pop();
corner_tracker.TrackCorners(prev_frame, curr_frame, mask, 100, tracked_corners, optical_flow);
for (int i = 0; i < (int)tracked_corners.size(); i++) {
//because optical flow is calculated between current frame and the frame_lag frame before it
//the actual value of the optical flow vector has to be normalized
Point2f normalized_optical_flow = optical_flow[i]*(1.0/(double)frame_lag);
line(ref_frame, tracked_corners[i], tracked_corners[i] + normalized_optical_flow, Scalar(0,255,0));
circle(ref_frame, tracked_corners[i], 2, Scalar(0,0,255));
}
imshow("window",ref_frame);
if((char)waitKey(30) == 27) {
break;
}
}
return 0;
}

файл заголовка углового трекера

#ifndef CORNER_TRACKER_H_
#define CORNER_TRACKER_H_
#include <opencv2/core/core.hpp>

struct CornerTrackerParameterBlock {
double lkt_max_bidirectioal_error;
int lkt_maxlevel;
int lkt_winsize;
int feature_blocksize;
double feature_k;
double feature_mindist;
double feature_quality_level;

//default constructor
CornerTrackerParameterBlock(void) :
lkt_max_bidirectioal_error(2.0),
lkt_maxlevel(3),
lkt_winsize(16),
feature_blocksize(3),
feature_k(0.04),
feature_mindist(5.0),
feature_quality_level(0.01)
{}
};

class CornerTracker {
public:
CornerTracker(const CornerTrackerParameterBlock& param);
void TrackCorners(const cv::Mat& prev_frame, const cv::Mat& curr_frame, const cv::Mat& mask, int max_corners, std::vector<cv::Point2f>& tracked_corners, std::vector<cv::Point2f>& optical_flow_vectors) const;
private:
void AddAdditionalCorners(const cv::Mat& curr_frame, const cv::Mat& mask, int max_corners, std::vector<cv::Point2f>& tracked_corners) const;
CornerTrackerParameterBlock m_param;
};

#endif //CORNER_TRACKER_H_

угловой трекер cpp файл

#include <iostream>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/video/tracking.hpp>
#include "corner_tracker.h"
using namespace std;
using namespace cv;

CornerTracker::CornerTracker(const CornerTrackerParameterBlock& param) :
m_param(param)
{}

void CornerTracker::AddAdditionalCorners(const cv::Mat& curr_frame, const cv::Mat& mask, int max_corners, std::vector<cv::Point2f>& tracked_corners) const {
//detect additional features
int additional_corners = max_corners - tracked_corners.size();
if (additional_corners <= 0) return;
//generate mask
Mat tmp_mask;
if (mask.rows != curr_frame.rows || mask.cols != curr_frame.cols || mask.type() != CV_8U) {
tmp_mask.create(curr_frame.rows, curr_frame.cols, CV_8U);
tmp_mask = Scalar::all(255);
}
else {
mask.copyTo(tmp_mask);
}
//mask out current points
for (const Point2f& p : tracked_corners) {
circle(tmp_mask, p, m_param.feature_mindist, Scalar::all(0), -1); //filled black circle
}
vector<Point2f> corners;
goodFeaturesToTrack(curr_frame, corners, additional_corners, m_param.feature_quality_level, m_param.feature_mindist, tmp_mask, m_param.feature_blocksize, true, m_param.feature_k );
for (const Point2f& p : corners) {
tracked_corners.push_back(p);
}
}

void CornerTracker::TrackCorners(const cv::Mat& prev_frame, const cv::Mat& curr_frame, const cv::Mat& mask, int max_corners, std::vector<cv::Point2f>& tracked_corners, std::vector<cv::Point2f>& optical_flow_vectors) const {
AddAdditionalCorners(curr_frame, mask, max_corners, tracked_corners);
vector<Point2f> prev_corners(tracked_corners);
vector<Point2f> next_corners(tracked_corners);
//optical flow corner tracking
vector<uchar> status1,status2;
vector<float> error1,error2;
calcOpticalFlowPyrLK(curr_frame, prev_frame, tracked_corners, prev_corners, status1, error1, Size(m_param.lkt_winsize,m_param.lkt_winsize), m_param.lkt_maxlevel, TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 30, 0.01), OPTFLOW_USE_INITIAL_FLOW);
calcOpticalFlowPyrLK(prev_frame, curr_frame, prev_corners, next_corners, status2, error2, Size(m_param.lkt_winsize,m_param.lkt_winsize), m_param.lkt_maxlevel, TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 30, 0.01), OPTFLOW_USE_INITIAL_FLOW);
//check tracked corner quality
vector<Point2f> temp_corners;
optical_flow_vectors.clear();
for (unsigned int i = 0; i < tracked_corners.size(); i++) {
if (status1[i] == 0 || status2[i] == 0) {
continue;
}
float bidirectional_error = norm(next_corners[i] - tracked_corners[i]);
//bidirectional error check
if (bidirectional_error > m_param.lkt_max_bidirectioal_error) {
continue;
}
optical_flow_vectors.push_back(tracked_corners[i] - prev_corners[i]);
temp_corners.push_back(tracked_corners[i]);
}
tracked_corners.swap(temp_corners);
}
0

Другие решения

На самом деле, я обнаружил, что моя проблема — ошибка преобразования типа float в int в моем коде.

В своем коде я просматривал все кадры и выполнял преобразование точек отслеживания оптического потока в точки IOS (CGPoint) и обратно. Во время этого процесса я случайно преобразовал из float в int (я использовал cv :: Point вместо cv :: Point2f).

Производительность ухудшалась при высоких fps, потому что ошибка накапливалась намного больше, так как отслеживание вызывается намного больше.

0

Это также может произойти, если качество видео изменится. При более низком FPS, но одинаковом kBPS, некоторые типы видеокодера (например, h.264) имеют больше битов для кодирования каждого кадра, что приводит к более высокому качеству.

0
По вопросам рекламы [email protected]