我正在尝试使用 OpenCV 创建简单的 blob 跟踪。我已经使用 findcontours 检测到了这些斑点。我想给这些 blob 一个常量 ID。
我已经收集了前一帧和当前帧中的 blob 列表。然后我取了前一帧中每个 blob 和当前帧之间的距离。我想知道还需要什么来跟踪 blob 并给它们一个 ID。我只是获取了前一帧和当前帧 blob 之间的距离,但是如何使用 blob 之间的测量距离为 blob 分配一致的 ID?
我正在尝试使用 OpenCV 创建简单的 blob 跟踪。我已经使用 findcontours 检测到了这些斑点。我想给这些 blob 一个常量 ID。
我已经收集了前一帧和当前帧中的 blob 列表。然后我取了前一帧中每个 blob 和当前帧之间的距离。我想知道还需要什么来跟踪 blob 并给它们一个 ID。我只是获取了前一帧和当前帧 blob 之间的距离,但是如何使用 blob 之间的测量距离为 blob 分配一致的 ID?
在第一帧中,您可以以任何方式分配 id,1 表示您找到的第一个,2 表示第二个......或者只是根据他们在集合中的位置给他们 ID。
然后在下一帧你将不得不使用最佳匹配。找到 blob,计算当前 blob 与前一个图像的所有 blob 之间的所有距离,并将每个前一个 ID 分配给最近的 blob。刚刚进入该字段的 Blob 将获得新的 ID。
现在你有两帧,你可以对下一帧进行运动预测。只需计算 blob 的先前位置和当前位置之间的 deltaX 和 deltaY。您可以使用此信息来猜测未来的位置。匹配这个未来的位置。
如果您没有太多重叠的 blob,并且每个帧之间的移动不是太快且不稳定,这应该可以工作。
通过多张图像使用评分系统可能会更准确:
获取前 3 或 5 张图像的位置。对于第一帧的任何斑点,在第 2 帧上寻找最近的斑点,计算速度(deltaX deltaY),寻找最接近第 3、4、5 帧的预测位置...总结预测位置和最近斑点之间的所有距离成为分数。使用第 2 帧上的第 2 个最近点执行相同操作(它将向另一个方向搜索)。分数越低,它最有可能是好的 blob。
如果你有很多 blob,你应该使用四叉树来加速进程。比较平方距离;它将避免大量的 sqrt 计算。
重要的是要知道您的 blob 通常如何移动以调整您的算法。
这是一个 Blob 跟踪的 OpenCV 代码示例:
#include "stdafx.h"
#include <opencv2\opencv.hpp>
IplImage* GetThresholdedImage(IplImage* img)
{
// Convert the image into an HSV image
IplImage* imgHSV = cvCreateImage(cvGetSize(img), 8, 3);
cvCvtColor(img, imgHSV, CV_BGR2HSV);
IplImage* imgThreshed = cvCreateImage(cvGetSize(img), 8, 1);
// Values 20,100,100 to 30,255,255 working perfect for yellow at around 6pm
cvInRangeS(imgHSV, cvScalar(112, 100, 100), cvScalar(124, 255, 255), imgThreshed);
cvReleaseImage(&imgHSV);
return imgThreshed;
}
int main()
{
// Initialize capturing live feed from the camera
CvCapture* capture = 0;
capture = cvCaptureFromCAM(0);
// Couldn't get a device? Throw an error and quit
if(!capture)
{
printf("Could not initialize capturing...\n");
return -1;
}
// The two windows we'll be using
cvNamedWindow("video");
cvNamedWindow("thresh");
// This image holds the "scribble" data...
// the tracked positions of the ball
IplImage* imgScribble = NULL;
// An infinite loop
while(true)
{
// Will hold a frame captured from the camera
IplImage* frame = 0;
frame = cvQueryFrame(capture);
// If we couldn't grab a frame... quit
if(!frame)
break;
// If this is the first frame, we need to initialize it
if(imgScribble == NULL)
{
imgScribble = cvCreateImage(cvGetSize(frame), 8, 3);
}
// Holds the yellow thresholded image (yellow = white, rest = black)
IplImage* imgYellowThresh = GetThresholdedImage(frame);
// Calculate the moments to estimate the position of the ball
CvMoments *moments = (CvMoments*)malloc(sizeof(CvMoments));
cvMoments(imgYellowThresh, moments, 1);
// The actual moment values
double moment10 = cvGetSpatialMoment(moments, 1, 0);
double moment01 = cvGetSpatialMoment(moments, 0, 1);
double area = cvGetCentralMoment(moments, 0, 0);
// Holding the last and current ball positions
static int posX = 0;
static int posY = 0;
int lastX = posX;
int lastY = posY;
posX = moment10/area;
posY = moment01/area;
// Print it out for debugging purposes
printf("position (%d,%d)\n", posX, posY);
// We want to draw a line only if its a valid position
if(lastX>0 && lastY>0 && posX>0 && posY>0)
{
// Draw a yellow line from the previous point to the current point
cvLine(imgScribble, cvPoint(posX, posY), cvPoint(lastX, lastY), cvScalar(0,255,255), 5);
}
// Add the scribbling image and the frame... and we get a combination of the two
cvAdd(frame, imgScribble, frame);
cvShowImage("thresh", imgYellowThresh);
cvShowImage("video", frame);
// Wait for a keypress
int c = cvWaitKey(10);
if(c!=-1)
{
// If pressed, break out of the loop
break;
}
// Release the thresholded image... we need no memory leaks.. please
cvReleaseImage(&imgYellowThresh);
delete moments;
}
// We're done using the camera. Other applications can now use it
cvReleaseCapture(&capture);
return 0;
}
您可以使用cvblobslib库进行斑点检测...