1

我一直在尝试开发一个简单的特征跟踪程序。用户用鼠标在屏幕上勾勒出一个区域,并为这个区域创建一个遮罩并传递给 goodFeaturesToTrack。然后将函数找到的特征绘制在屏幕上(由蓝色圆圈表示)。

接下来,我将函数返回的特征向量传递给 calcOpticalFlowPyrLk 并在屏幕上绘制结果向量(由绿色圆圈表示)。尽管程序正确地跟踪了流动方向,但由于某种原因,calcOpticalFlow 函数输出的特征与屏幕上对象的位置不一致。

我觉得这似乎是我使用的逻辑中的一个小错误,但我似乎无法分解它,我非常感谢你们的帮助。

我已经在下面发布了我的代码,对于全局变量和混乱的结构,我深表歉意。我目前只是在测试,并计划在运行后立即清理并转换为 OOP 格式。

同样,这是我上传的 YouTube 视频的链接,该视频演示了我正在打击的行为。

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;
}
4

1 回答 1

1

在我看来,您不能camera.set(CV_CAP_PROP_POS_FRAMES, currentFrame)在网络摄像头上使用,但我对此并不积极。

相反,我建议您将前一帧保存在您的 prevFrame 变量中。

作为一个例子,我可以向你推荐这个工作代码,我只在 while 循环内进行更改,并在所有添加之前添加注释:

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);
    }

    // new lines
    if(prevFrame.empty()){
            prevFrame = cameraFrame;
            continue;
    }
    // end new lines

    //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;
    // new line
    nextFrame = cameraFrame;
    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);

    // old = new
    // new line
    prevFrame = cameraFrame.clone();

}

于 2013-07-03T09:24:44.847 回答