如何计算 Lucas Kanade 流
How to compute Lucas Kanade flow
我目前正在做一个对象跟踪的项目,使用过c++、opencv。我已经成功地使用 Farneback dense optical flow 来实现分割方法,例如 k 均值(使用每帧中的位移)。现在我想用 Lucas Kanade 稀疏方法做同样的事情。但是这个函数的输出是:
nextPts – 二维点的输出向量(具有单精度浮点坐标),包含计算出的第二幅图像中输入特征的新位置;当传递 OPTFLOW_USE_INITIAL_FLOW 标志时,向量的大小必须与输入中的大小相同。
(如官方网站所述)
我的问题是 例如,我将如何获得 Mat 流的结果。到目前为止我已经尝试过:
// 实现 Lucas Kanade 算法
cvCalcOpticalFlowPyrLK(frame1_1C, frame2_1C, pyramid1, pyramid2,
frame1_features, frame2_features, number_of_features,
optical_flow_window, 5, optical_flow_found_feature,
optical_flow_feature_error, optical_flow_termination_criteria,
0);
// Calculate each feature point's coordinates in every frame
CvPoint p,q;
p.x = (int) frame1_features[i].x;
p.y = (int) frame1_features[i].y;
q.x = (int) frame2_features[i].x;
q.y = (int) frame2_features[i].y;
// Creating the arrows for imshow
angle = atan2((double) p.y - q.y, (double) p.x - q.x);
hypotenuse = sqrt(square(p.y - q.y) + square(p.x - q.x));
/* Here we lengthen the arrow by a factor of three. */
q.x = (int) (p.x - 3 * hypotenuse * cos(angle));
q.y = (int) (p.y - 3 * hypotenuse * sin(angle));
cvLine(frame1, p, q, line_color, line_thickness, CV_AA, 0);
p.x = (int) (q.x + 9 * cos(angle + pi / 4));
p.y = (int) (q.y + 9 * sin(angle + pi / 4));
cvLine(frame1, p, q, line_color, line_thickness, CV_AA, 0);
p.x = (int) (q.x + 9 * cos(angle - pi / 4));
p.y = (int) (q.y + 9 * sin(angle - pi / 4));
cvLine(frame1, p, q, line_color, line_thickness, CV_AA, 0);
allocateOnDemand(&framenew, frame_size, IPL_DEPTH_8U, 3);
cvConvertImage(frame1, framenew, CV_CVTIMG_FLIP);
cvShowImage("Optical Flow", framenew);
这是光流演示。我应该如何获得类似于 Farneback 光流结果的 Mat 流?
更新:非常好的答案。但是现在我在显示 kmeans 图像时遇到了问题。对于 farneback,我使用了:
cv::kmeans(m, K, bestLabels,
TermCriteria( CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 10, 1.0),
3, KMEANS_PP_CENTERS, centers);
int colors[K];
for (int i = 0; i < K; i++) {
colors[i] = 255 / (i + 1);
}
namedWindow("Kmeans", WINDOW_NORMAL);
Mat clustered = Mat(flow.rows, flow.cols, CV_32F);
for (int i = 0; i < flow.cols * flow.rows; i++) {
clustered.at<float>(i / flow.cols, i % flow.cols) =
(float) (colors[bestLabels.at<int>(0, i)]);
}
clustered.convertTo(clustered, CV_8U);
imshow("Kmeans", clustered);
有什么想法吗? ?
要获得类似 Farneback 算法的图像,您必须首先了解输出是什么。
在 OpenCV 文档中,您有:
prev(y,x) ~ next(y + flow(y,x)[1], x +flow(y,x)[0])
因此,它是一个矩阵,其中包含图像 1 和图像 2 之间的位移。假设您不计算的点将没有移动 0,0;你可以模拟这个,你只需要为具有新位置 (x', y')
:
的每个点 (x,y)
cv::Mat LKFlowMatrix(img.rows, img.cols, CV_32FC2, cv::Scalar(0,0));
LKFlowMatrix.at<cv::Vec2f>(y,x) = cv::Vec2f(x-x', y-y') ;
此外,不要忘记过滤状态为 0
的 "not found points"
顺便说一下,你的函数不是它的 opencv c++ 版本:
cvCalcOpticalFlowPyrLK
在 C++ 中应该是 cv::calcOpticalFlowFarneback
cvShowImage
在c++中应该是cv::imshow
等等
** 更新**
既然你需要的是 kmeans 的输入(我想那是 OpenCV 版本),而你只想使用稀疏点,那么你可以这样做:
cv::Mat prevImg, nextImg;
// load your images
std::vector<cv:Point2f> initial_points, new_points;
// fill the initial points vector
std::vector<uchar> status;
std::vector<float> error;
cv::calcOpticalFlowPyrLK(prevImage, nextImage, initial_points, new_points, status, errors);
std::vector<cv::Vec2f> vectorForKMeans;
for(size_t t = 0; t < status.size(); t++){
if(status[t] != 0)
vectorForKmeans.push_back(cv::Vec2f(initial_points[i] - new_points[i]));
}
// Do kmeans to vectorForKMeans
我目前正在做一个对象跟踪的项目,使用过c++、opencv。我已经成功地使用 Farneback dense optical flow 来实现分割方法,例如 k 均值(使用每帧中的位移)。现在我想用 Lucas Kanade 稀疏方法做同样的事情。但是这个函数的输出是:
nextPts – 二维点的输出向量(具有单精度浮点坐标),包含计算出的第二幅图像中输入特征的新位置;当传递 OPTFLOW_USE_INITIAL_FLOW 标志时,向量的大小必须与输入中的大小相同。
(如官方网站所述)
我的问题是 例如,我将如何获得 Mat 流的结果。到目前为止我已经尝试过:
// 实现 Lucas Kanade 算法
cvCalcOpticalFlowPyrLK(frame1_1C, frame2_1C, pyramid1, pyramid2,
frame1_features, frame2_features, number_of_features,
optical_flow_window, 5, optical_flow_found_feature,
optical_flow_feature_error, optical_flow_termination_criteria,
0);
// Calculate each feature point's coordinates in every frame
CvPoint p,q;
p.x = (int) frame1_features[i].x;
p.y = (int) frame1_features[i].y;
q.x = (int) frame2_features[i].x;
q.y = (int) frame2_features[i].y;
// Creating the arrows for imshow
angle = atan2((double) p.y - q.y, (double) p.x - q.x);
hypotenuse = sqrt(square(p.y - q.y) + square(p.x - q.x));
/* Here we lengthen the arrow by a factor of three. */
q.x = (int) (p.x - 3 * hypotenuse * cos(angle));
q.y = (int) (p.y - 3 * hypotenuse * sin(angle));
cvLine(frame1, p, q, line_color, line_thickness, CV_AA, 0);
p.x = (int) (q.x + 9 * cos(angle + pi / 4));
p.y = (int) (q.y + 9 * sin(angle + pi / 4));
cvLine(frame1, p, q, line_color, line_thickness, CV_AA, 0);
p.x = (int) (q.x + 9 * cos(angle - pi / 4));
p.y = (int) (q.y + 9 * sin(angle - pi / 4));
cvLine(frame1, p, q, line_color, line_thickness, CV_AA, 0);
allocateOnDemand(&framenew, frame_size, IPL_DEPTH_8U, 3);
cvConvertImage(frame1, framenew, CV_CVTIMG_FLIP);
cvShowImage("Optical Flow", framenew);
这是光流演示。我应该如何获得类似于 Farneback 光流结果的 Mat 流?
更新:非常好的答案。但是现在我在显示 kmeans 图像时遇到了问题。对于 farneback,我使用了:
cv::kmeans(m, K, bestLabels,
TermCriteria( CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 10, 1.0),
3, KMEANS_PP_CENTERS, centers);
int colors[K];
for (int i = 0; i < K; i++) {
colors[i] = 255 / (i + 1);
}
namedWindow("Kmeans", WINDOW_NORMAL);
Mat clustered = Mat(flow.rows, flow.cols, CV_32F);
for (int i = 0; i < flow.cols * flow.rows; i++) {
clustered.at<float>(i / flow.cols, i % flow.cols) =
(float) (colors[bestLabels.at<int>(0, i)]);
}
clustered.convertTo(clustered, CV_8U);
imshow("Kmeans", clustered);
有什么想法吗? ?
要获得类似 Farneback 算法的图像,您必须首先了解输出是什么。
在 OpenCV 文档中,您有:
prev(y,x) ~ next(y + flow(y,x)[1], x +flow(y,x)[0])
因此,它是一个矩阵,其中包含图像 1 和图像 2 之间的位移。假设您不计算的点将没有移动 0,0;你可以模拟这个,你只需要为具有新位置 (x', y')
:
(x,y)
cv::Mat LKFlowMatrix(img.rows, img.cols, CV_32FC2, cv::Scalar(0,0));
LKFlowMatrix.at<cv::Vec2f>(y,x) = cv::Vec2f(x-x', y-y') ;
此外,不要忘记过滤状态为 0
的 "not found points"顺便说一下,你的函数不是它的 opencv c++ 版本:
cvCalcOpticalFlowPyrLK
在 C++ 中应该是 cv::calcOpticalFlowFarneback
cvShowImage
在c++中应该是cv::imshow
等等
** 更新**
既然你需要的是 kmeans 的输入(我想那是 OpenCV 版本),而你只想使用稀疏点,那么你可以这样做:
cv::Mat prevImg, nextImg;
// load your images
std::vector<cv:Point2f> initial_points, new_points;
// fill the initial points vector
std::vector<uchar> status;
std::vector<float> error;
cv::calcOpticalFlowPyrLK(prevImage, nextImage, initial_points, new_points, status, errors);
std::vector<cv::Vec2f> vectorForKMeans;
for(size_t t = 0; t < status.size(); t++){
if(status[t] != 0)
vectorForKmeans.push_back(cv::Vec2f(initial_points[i] - new_points[i]));
}
// Do kmeans to vectorForKMeans