Opencv 绘制calcOpticalFlow'时跟踪不准确;s输出的特征向量
我一直在尝试开发一个简单的功能跟踪程序。用户用鼠标在屏幕上勾勒出一个区域,并为该区域创建一个遮罩,并将其传递给goodFeaturesToTrack。然后在屏幕上绘制函数找到的特征(用蓝色圆圈表示) 接下来,我将函数返回的特征向量传递给calcOpticalFlowPyrLk,并在屏幕上绘制点的结果向量(由绿色圆圈表示)。尽管程序正确跟踪流动方向,但由于某些原因,“calcOpticalFlow”功能输出的功能与对象在屏幕上的位置不一致 我觉得这是我用的逻辑中的一个小错误,但我似乎无法分解它,我真的很感谢你们的帮助 我已经在下面发布了我的代码,对于全局变量和混乱的结构,我深表歉意。我现在正在测试,并计划在运行OOP后尽快清理并转换为OOP格式 还有,这里是我上传的YouTube视频的一个链接,它展示了我正在与之斗争的行为Opencv 绘制calcOpticalFlow'时跟踪不准确;s输出的特征向量,opencv,opticalflow,feature-tracking,Opencv,Opticalflow,Feature Tracking,我一直在尝试开发一个简单的功能跟踪程序。用户用鼠标在屏幕上勾勒出一个区域,并为该区域创建一个遮罩,并将其传递给goodFeaturesToTrack。然后在屏幕上绘制函数找到的特征(用蓝色圆圈表示) 接下来,我将函数返回的特征向量传递给calcOpticalFlowPyrLk,并在屏幕上绘制点的结果向量(由绿色圆圈表示)。尽管程序正确跟踪流动方向,但由于某些原因,“calcOpticalFlow”功能输出的功能与对象在屏幕上的位置不一致 我觉得这是我用的逻辑中的一个小错误,但我似乎无法分解它,我
bool drawingBox = false;
bool destroyBox = false;
bool targetAcquired = false;
bool featuresFound = false;
CvRect box;
int boxCounter = 0;
cv::Point objectLocation;
cv::Mat prevFrame, nextFrame, prevFrame_1C, nextFrame_1C;
std::vector<cv::Point2f> originalFeatures, newFeatures, baseFeatures;
std::vector<uchar> opticalFlowFeatures;
std::vector<float> opticalFlowFeaturesError;
cv::TermCriteria opticalFlowTermination = cv::TermCriteria(CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 20, 0.3);
cv::Mat mask;
cv::Mat clearMask;
long currentFrame = 0;
void draw(cv::Mat image, CvRect rectangle)
{
if (drawingBox)
{
cv::rectangle(image, cv::Point(box.x, box.y), cv::Point(box.x + box.width, box.y + box.height), cv::Scalar(225, 238 , 81), 2);
CvRect rectangle2 = cvRect(box.x, box.y, box.width, box.height);
}
if (featuresFound)
{
for (int i = 0; i < originalFeatures.size(); i++)
{
cv::circle(image, baseFeatures[i], 4, cv::Scalar(255, 0, 0), 1, 8, 0);
cv::circle(image, newFeatures[i], 4, cv::Scalar(0, 255, 0),1, 8, 0);
cv::line(image, baseFeatures[i], newFeatures[i], cv::Scalar(255, 0, 0), 2, CV_AA);
}
}
}
void findFeatures(cv::Mat mask)
{
if (!featuresFound && targetAcquired)
{
cv::goodFeaturesToTrack(prevFrame_1C, baseFeatures, 200, 0.1, 0.1, mask);
originalFeatures= baseFeatures;
featuresFound = true;
std::cout << "Number of Corners Detected: " << originalFeatures.size() << std::endl;
for(int i = 0; i < originalFeatures.size(); i++)
{
std::cout << "Corner Location " << i << ": " << originalFeatures[i].x << "," << originalFeatures[i].y << std::endl;
}
}
}
void trackFeatures()
{
cv::calcOpticalFlowPyrLK(prevFrame_1C, nextFrame_1C, originalFeatures, newFeatures, opticalFlowFeatures, opticalFlowFeaturesError, cv::Size(30,30), 5, opticalFlowTermination);
originalFeatures = newFeatures;
}
void mouseCallback(int event, int x, int y, int flags, void *param)
{
cv::Mat frame;
frame = *((cv::Mat*)param);
switch(event)
{
case CV_EVENT_MOUSEMOVE:
{
if(drawingBox)
{
box.width = x-box.x;
box.height = y-box.y;
}
}
break;
case CV_EVENT_LBUTTONDOWN:
{
drawingBox = true;
box = cvRect (x, y, 0, 0);
targetAcquired = false;
cv::destroyWindow("Selection");
}
break;
case CV_EVENT_LBUTTONUP:
{
drawingBox = false;
featuresFound = false;
boxCounter++;
std::cout << "Box " << boxCounter << std::endl;
std::cout << "Box Coordinates: " << box.x << "," << box.y << std::endl;
std::cout << "Box Height: " << box.height << std::endl;
std::cout << "Box Width: " << box.width << std:: endl << std::endl;
if(box.width < 0)
{
box.x += box.width;
box.width *= -1;
}
if(box.height < 0)
{
box.y +=box.height;
box.height *= -1;
}
objectLocation.x = box.x;
objectLocation.y = box.y;
targetAcquired = true;
}
break;
case CV_EVENT_RBUTTONUP:
{
destroyBox = true;
}
break;
}
}
int main ()
{
const char *name = "Boundary Box";
cv::namedWindow(name);
cv::VideoCapture camera;
cv::Mat cameraFrame;
int cameraNumber = 0;
camera.open(cameraNumber);
camera >> cameraFrame;
cv::Mat mask = cv::Mat::zeros(cameraFrame.size(), CV_8UC1);
cv::Mat clearMask = cv::Mat::zeros(cameraFrame.size(), CV_8UC1);
if (!camera.isOpened())
{
std::cerr << "ERROR: Could not access the camera or video!" << std::endl;
}
cv::setMouseCallback(name, mouseCallback, &cameraFrame);
while(true)
{
if (destroyBox)
{
cv::destroyAllWindows();
break;
}
camera >> cameraFrame;
if (cameraFrame.empty())
{
std::cerr << "ERROR: Could not grab a camera frame." << std::endl;
exit(1);
}
camera.set(CV_CAP_PROP_POS_FRAMES, currentFrame);
camera >> prevFrame;
cv::cvtColor(prevFrame, prevFrame_1C, cv::COLOR_BGR2GRAY);
camera.set(CV_CAP_PROP_POS_FRAMES, currentFrame ++);
camera >> nextFrame;
cv::cvtColor(nextFrame, nextFrame_1C, cv::COLOR_BGR2GRAY);
if (targetAcquired)
{
cv::Mat roi (mask, cv::Rect(box.x, box.y, box.width, box.height));
roi = cv::Scalar(255, 255, 255);
findFeatures(mask);
clearMask.copyTo(mask);
trackFeatures();
}
draw(cameraFrame, box);
cv::imshow(name, cameraFrame);
cv::waitKey(20);
}
cv::destroyWindow(name);
return 0;
}
bool drawingBox=false;
bool-box=false;
bool targetAcquired=假;
bool featuresFound=false;
CvRect盒;
int-boxCounter=0;
cv::点对象位置;
cv::Mat prevFrame,nextFrame,prevFrame_1C,nextFrame_1C;
std::矢量原始特征、新特征、基本特征;
std::矢量光学流特征;
std::矢量光流特性错误;
cv::TermCriteria opticalFlowTermination=cv::TermCriteria(cv_TERMCRIT_ITER | cv_TERMCRIT_EPS,20,0.3);
cv::Mat面罩;
cv::Mat clearMask;
长currentFrame=0;
空心绘制(cv::Mat图像,CvRect矩形)
{
if(牵引箱)
{
cv::矩形(图像,cv::点(box.x,box.y),cv::点(box.x+box.width,box.y+box.height),cv::标量(225,238,81),2);
CvRect rectangle2=CvRect(box.x,box.y,box.width,box.height);
}
如果(功能查找)
{
对于(int i=0;i std::cout在我看来,你不能在网络摄像机上使用camera.set(CV\u CAP\u PROP\u POS\u FRAMES,currentFrame)
,但我对此并不乐观
相反,我建议您将前一帧保存在prevFrame变量中
例如,我可以建议您使用此工作代码,我只在while循环中进行更改,并在所有添加之前添加注释:
while(true)
{
如果(删除框)
{
cv::destroyAllWindows();
打破
}
照相机>>照相机框架;
if(cameraFrame.empty())
{
标准:cerr框架;
cv::CVT颜色(prevFrame、prevFrame_1C、cv::COLOR_BGr2灰色);
//摄像机设置(CV_CAP_PROP_POS_FRAMES,currentFrame++);
//相机>>下一帧;
//新线
下一帧=摄影机帧;
cv::CVT颜色(下一帧、下一帧、cv::颜色为灰色);
如果(targetAcquired)
{
cv::Mat roi(遮罩,cv::Rect(box.x,box.y,box.width,box.height));
roi=cv::标量(255、255、255);
findFeatures(掩码);
clearMask.copyTo(掩码);
轨迹特征();
}
绘图(摄像机框架、盒子);
cv::imshow(名称、摄像机框架);
cv::waitKey(20);
//旧=新
//新线
prevFrame=cameraFrame.clone();
}在我看来,你不能在网络摄像头上使用摄像头.set(CV\u CAP\u PROP\u POS\u FRAMES,currentFrame)
,但我对此并不乐观
相反,我建议您将前一帧保存在prevFrame变量中
例如,我可以建议您使用此工作代码,我只在while循环中进行更改,并在所有添加之前添加注释:
while(true)
{
如果(删除框)
{
cv::destroyAllWindows();
打破
}
照相机>>照相机框架;
if(cameraFrame.empty())
{
标准:cerr框架;
cv::CVT颜色(prevFrame、prevFrame_1C、cv::COLOR_BGr2灰色);
//摄像机设置(CV_CAP_PROP_POS_FRAMES,currentFrame++);
//相机>>下一帧;
//新线
下一帧=摄影机帧;
cv::CVT颜色(下一帧、下一帧、cv::颜色为灰色);
如果(targetAcquired)
{
cv::Mat roi(遮罩,cv::Rect(box.x,box.y,box.width,box.height));
roi=cv::标量(255、255、255);
findFeatures(掩码);
clearMask.copyTo(掩码);
轨迹特征();
}
绘图(摄像机框架、盒子);
cv::imshow(名称、摄像机框架);
cv::waitKey(20);
//旧=新
//新线
prevFrame=cameraFrame.clone();
}运动的方向似乎正确,因此它似乎是一个比例问题。你能试着将点乘以某个值吗?是的,运动的方向确实是正确的,但我想完全理解它为什么不匹配,以便我可以相应地进行校正。我不想走老生常谈的路线,只是将其缩放到by一些任意值。找出比例是什么将有助于找出为什么需要该比例是正确的。可能是该比例是ROI和捕获图像的实际大小之间的比例。你提出了一个很好的观点!我肯定会研究它并报告我的结果。运动的方向似乎正确t、 所以这似乎是一个比例的问题。你能试着用一个特定的值乘以这些点吗?是的,运动的方向确实是正确的,但我想完全压缩