我正在寻找人类运动跟踪的实现方法,这在多目标运动检测中也有讨论,通过从多个视频帧中提取,使用差分分析和卢卡斯-卡纳德光流法来实现。
我找到了相关的科学论文,发现我们需要使用连通组件过滤连通组件来进行连续的运动跟踪,但我不知道如何进行这个过程。我只需要骨架化轨迹和人类步态运动的坐标。
我使用的是OpenCV和C++,但OpenCV中关于对象检测的文档对我来说不够用。我来自医学背景,这是一个儿科项目的部分内容。
我找到了这段代码运动检测,并尝试执行它(还不知道它是否能检测和跟踪运动)。然而,它返回了这些错误,我感到困惑,因为这些错误似乎很简单,其他评论提到他们能够运行这段代码。但我无法解决这些错误,也无法理解它们发生的原因。我使用的是OpenCV 2.3,以下是错误列表:
- 无法打开源文件 stdafx.h
- 警告 C4996: ‘fopen’: 此函数或变量可能不安全。请考虑使用 fopen_s 代替。要禁用弃用警告,请使用 _CRT_SECURE_NO_WARNINGS。请查看在线帮助以获取详细信息。
- 错误 C2086: ‘CvSize imgSize’ : 重新定义
- 错误 C2065: ‘temp’ : 未声明的标识符
- 错误 C4430: 缺少类型说明符 – 假定为 int。注意:C++ 不支持默认的 int
- 错误 C2365: ‘cvReleaseImage’ : 重新定义;之前的定义是 ‘函数’1> c:\opencv2.3\opencv\build\include\opencv2\core\core_c.h(87) : 查看 ‘cvReleaseImage’ 的声明
- 错误 C2065: ‘difference’ : 未声明的标识符
- 错误 C4430: 缺少类型说明符 – 假定为 int。注意:C++ 不支持默认的 int
- 错误 C2365: ‘cvReleaseImage’ : 重新定义;之前的定义是 ‘函数’1> c:\opencv2.3\opencv\build\include\opencv2\core\core_c.h(87) : 查看 ‘cvReleaseImage’ 的声明
- 错误 C2065: ‘greyImage’ : 未声明的标识符
- 错误 C4430: 缺少类型说明符 – 假定为 int。注意:C++ 不支持默认的 int
- 错误 C2365: ‘cvReleaseImage’ : 重新定义;之前的定义是 ‘函数’
- \opencv2.3\opencv\build\include\opencv2\core\core_c.h(87) : 查看 ‘cvReleaseImage’ 的声明错误 C2065: ‘movingAverage’ : 未声明的标识符错误 C4430: 缺少类型说明符 – 假定为 int。注意:C++ 不支持默认的 int错误 C2365: ‘cvReleaseImage’ : 重新定义;之前的定义是 ‘函数’-1> c:\opencv2.3\opencv\build\include\opencv2\core\core_c.h(87) : 查看 ‘cvReleaseImage’ 的声明错误 C4430: 缺少类型说明符 – 假定为 int。注意:C++ 不支持默认的 int错误 C2365: ‘cvDestroyWindow’ : 重新定义;之前的定义是 ‘函数’
- c:\opencv2.3\opencv\build\include\opencv2\highgui\highgui_c.h(136) : 查看 ‘cvDestroyWindow’ 的声明
- 错误 C2440: ‘initializing’ : 无法从 ‘const char [10]’ 转换为 ‘int’-1> 没有上下文可以进行此转换错误 C2065: ‘input’ : 未声明的标识符错误 C4430: 缺少类型说明符 – 假定为 int。注意:C++ 不支持默认的 int
- 错误 C2365: ‘cvReleaseCapture’ : 重新定义;之前的定义是 ‘函数’-1> c:\opencv2.3\opencv\build\include\opencv2\highgui\highgui_c.h(311) : 查看 ‘cvReleaseCapture’ 的声明错误 C2065: ‘outputMovie’ : 未声明的标识符
- 错误 C4430: 缺少类型说明符 – 假定为 int。注意:C++ 不支持默认的 int错误 C2365: ‘cvReleaseVideoWriter’ : 重新定义;之前的定义是 ‘函数’-1 c:\opencv2.3\opencv\build\include\opencv2\highgui\highgui_c.h(436) : 查看 ‘cvReleaseVideoWriter’ 的声明错误 C2059: 语法错误 : ‘return’========== 构建: 0 成功, 1 失败, 0 最新, 0 跳过 ==========
代码
// MotionDetection.cpp : 定义控制台应用程序的入口点。//// Contourold.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include "iostream"#include "stdlib.h"// OpenCV 包含文件。#include "cv.h"#include "highgui.h"#pragma comment(lib,"cv.lib")#pragma comment(lib,"cxcore.lib")#pragma comment(lib,"highgui.lib")using namespace std;int main(int argc, char* argv[]){//创建一个新窗口。cvNamedWindow("My Window", CV_WINDOW_AUTOSIZE);//创建一个新的电影捕获对象。CvCapture *input;//分配电影以进行捕获。//inputMovie = cvCaptureFromAVI("vinoth.avi");char *fileName = "E:\\highway.avi";//char *fileName = "D:\\Profile\\AVI\\cardriving.wmv";input = cvCaptureFromFile(fileName);//if (!input)//cout << "Can't open file" << fileName < ;//图像的大小。CvSize imgSize;IplImage* frame = cvQueryFrame(input);CvSize imgSize = cvGetSize(frame);//程序中使用的图像。IplImage* greyImage = cvCreateImage( imgSize, IPL_DEPTH_8U, 1);IplImage* colourImage;IplImage* movingAverage = cvCreateImage( imgSize, IPL_DEPTH_32F, 3);IplImage* difference;IplImage* temp;IplImage* motionHistory = cvCreateImage( imgSize, IPL_DEPTH_8U, 3);//用于环绕人的矩形。CvRect bndRect = cvRect(0,0,0,0);//矩形边缘的点。CvPoint pt1, pt2;//创建一个字体对象。CvFont font;//创建输出视频。char* outFilename = argc==2 ? argv[1] : "E:\\outputMovie.avi";CvVideoWriter* outputMovie = cvCreateVideoWriter(outFilename,CV_FOURCC('F', 'L', 'V', 'I'), 29.97, cvSize(720, 576));//逐帧捕获电影。int prevX = 0;int numPeople = 0;//用于将整数转换为字符串时保存人数的缓冲区。char wow[65];//环绕移动对象的矩形的中点 X 位置。int avgX = 0;//指示这是帧循环中的第一次。bool first = true;//指示在对象进入建筑物之间的区域之前,最接近左边界的轮廓。int closestToLeft = 0;//同上,但对于右边界。int closestToRight = 320;//继续处理帧...for(;;){//从输入视频中获取一帧。colourImage = cvQueryFrame(input);//如果没有更多帧,则跳出 for 循环。if( !colourImage ){break;}//如果这是第一次,则初始化图像。if(first){difference = cvCloneImage(colourImage);temp = cvCloneImage(colourImage);cvConvertScale(colourImage, movingAverage, 1.0, 0.0);first = false;}//否则,计算运动的运行平均值。else{cvRunningAvg(colourImage, movingAverage, 0.020, NULL);}//转换移动平均值的比例。cvConvertScale(movingAverage,temp, 1.0, 0.0);//从移动平均值中减去当前帧。cvAbsDiff(colourImage,temp,difference);//将图像转换为灰度。cvCvtColor(difference,greyImage,CV_RGB2GRAY);//将图像转换为黑白。cvThreshold(greyImage, greyImage, 70, 255, CV_THRESH_BINARY);//膨胀和侵蚀以获取人的 blobs。cvDilate(greyImage, greyImage, 0, 18);cvErode(greyImage, greyImage, 0, 10);//查找帧中移动图像的轮廓。CvMemStorage* storage = cvCreateMemStorage(0);CvSeq* contour = 0;cvFindContours( greyImage, storage, &contour, sizeof(CvContour), CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );//处理当前帧中的每个移动轮廓...for( ; contour != 0; contour = contour->h_next ){//获取移动对象周围的边界矩形。bndRect = cvBoundingRect(contour, 0);pt1.x = bndRect.x;pt1.y = bndRect.y;pt2.x = bndRect.x + bndRect.width;pt2.y = bndRect.y + bndRect.height;//获取移动轮廓的平均 X 位置。avgX = (pt1.x + pt2.x) / 2;//如果轮廓在建筑物的边缘内...if(avgX > 90 && avgX < 250){//如果之前的轮廓在左边界内 2 个单位...if(closestToLeft >= 88 && closestToLeft <= 90){//如果当前 X 位置大于之前的...if(avgX > prevX){//增加人数。numPeople++;//重置最接近左边界的指示器。closestToLeft = 0;}}//否则,如果之前的轮廓在右边界内 2 个单位...else if(closestToRight >= 250 && closestToRight <= 252){//如果当前 X 位置小于之前的...if(avgX < prevX){//增加人数。numPeople++;//重置最接近右边界的计数器。closestToRight = 320;}}//在移动对象周围绘制边界矩形。cvRectangle(colourImage, pt1, pt2, CV_RGB(255,0,0), 1);}//如果当前对象更接近左边界但仍未越过它,则将最接近左边界的计数器更改为此值。if(avgX > closestToLeft && avgX <= 90){closestToLeft = avgX;}//如果当前对象更接近右边界但仍未越过它,则将最接近右边界的计数器更改为此值。if(avgX < closestToRight && avgX >= 250){closestToRight = avgX;}//保存当前 X 值以在下一次迭代中用作之前的值。prevX = avgX;}//保存当前 X 值以在下一次迭代中用作之前的值。prevX = avgX;}//在输出帧的顶部写入计数的人数。cvInitFont(&font, CV_FONT_HERSHEY_SIMPLEX, 0.8, 0.8, 0, 2);cvPutText(colourImage, _itoa(numPeople, wow, 10), cvPoint(60, 200), &font, cvScalar(0, 0, 300));//显示帧。cvShowImage("My Window", colourImage);//等待用户查看。cvWaitKey(10);//将帧写入输出电影。cvWriteFrame(outputMovie, colourImage);}// 销毁图像、电影和窗口。cvReleaseImage(&temp);cvReleaseImage(&difference);cvReleaseImage(&greyImage);cvReleaseImage(&movingAverage);cvDestroyWindow("My Window");cvReleaseCapture(&input);cvReleaseVideoWriter(&outputMovie);return 0;}
- 请帮助解决这些错误和问题。
- 如何进行运动(人类)跟踪,返回轨迹的坐标,可能通过骨架化方法实现。
回答:
1.) 我猜你直接从网站上复制了这段代码(如果我错了,请纠正我..)。然而,由于你使用的是OpenCV 2.3,所以大多数API都在不同的模块中。你应该包含以下文件…
#include <opencv/core/core.hpp>#include <opencv/highgui/highgui.hpp>#include <opencv/imgproc/imgproc.hpp>
以及相应的库文件。
2.) 对于过滤连通组件,你可以使用cvblob库。我认为OpenCV之前提供的旧Blob库是使用VC 6构建的,所以可能需要stdafx.h
3.) 慢慢查看代码以找出一些语法和重新声明错误。
编辑后的代码
#include <iostream>#include "stdlib.h"#include <opencv2/core/core.hpp>#include <opencv2/highgui/highgui.hpp>#include <opencv2/imgproc/imgproc.hpp>#include "cv.h"#include "highgui.h"using namespace std;using namespace cv;int main(int argc, char* argv[]){ cvNamedWindow("My Window", CV_WINDOW_AUTOSIZE); CvCapture *input; //char *fileName = "E:\\highway.avi"; input = cvCaptureFromCAM(0); //input = cvCaptureFromFile(fileName); CvSize imgSize; IplImage* frame = cvQueryFrame(input); imgSize = cvGetSize(frame); IplImage* greyImage = cvCreateImage( imgSize, IPL_DEPTH_8U, 1); IplImage* colourImage; IplImage* movingAverage = cvCreateImage( imgSize, IPL_DEPTH_32F, 3); IplImage* difference; IplImage* temp; IplImage* motionHistory = cvCreateImage( imgSize, IPL_DEPTH_8U, 3); CvRect bndRect = cvRect(0,0,0,0); CvPoint pt1, pt2; CvFont font; char* outFilename = argc==2 ? argv[1] : "E:\\outputMovie.avi"; CvVideoWriter* outputMovie = cvCreateVideoWriter(outFilename, CV_FOURCC('F', 'L', 'V', 'I'), 29.97, cvSize(720, 576)); int prevX = 0; int numPeople = 0; char wow[65]; int avgX = 0; bool first = true; int closestToLeft = 0; int closestToRight = 320; for(;;) { colourImage = cvQueryFrame(input); if( !colourImage ) { break; } if(first) { difference = cvCloneImage(colourImage); temp = cvCloneImage(colourImage); cvConvertScale(colourImage, movingAverage, 1.0, 0.0); first = false; } else { cvRunningAvg(colourImage, movingAverage, 0.020, NULL); } cvConvertScale(movingAverage,temp, 1.0, 0.0); cvAbsDiff(colourImage,temp,difference); cvCvtColor(difference,greyImage,CV_RGB2GRAY); cvThreshold(greyImage, greyImage, 70, 255, CV_THRESH_BINARY); cvDilate(greyImage, greyImage, 0, 18); cvErode(greyImage, greyImage, 0, 10); CvMemStorage* storage = cvCreateMemStorage(0); CvSeq* contour = 0; cvFindContours( greyImage, storage, &contour, sizeof(CvContour), CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE ); for( ; contour != 0; contour = contour->h_next ) { bndRect = cvBoundingRect(contour, 0); pt1.x = bndRect.x; pt1.y = bndRect.y; pt2.x = bndRect.x + bndRect.width; pt2.y = bndRect.y + bndRect.height; avgX = (pt1.x + pt2.x) / 2; if(avgX > 90 && avgX < 250) { if(closestToLeft >= 88 && closestToLeft <= 90) { if(avgX > prevX) { numPeople++; closestToLeft = 0; } } else if(closestToRight >= 250 && closestToRight <= 252) { if(avgX < prevX) { numPeople++; closestToRight = 320; } } cvRectangle(colourImage, pt1, pt2, CV_RGB(255,0,0), 1); } if(avgX > closestToLeft && avgX <= 90) { closestToLeft = avgX; } if(avgX < closestToRight && avgX >= 250) { closestToRight = avgX; } prevX = avgX; prevX = avgX; } cvInitFont(&font, CV_FONT_HERSHEY_SIMPLEX, 0.8, 0.8, 0, 2); cvPutText(colourImage, _itoa(numPeople, wow, 10), cvPoint(60, 200), &font, cvScalar(0, 0, 300)); cvShowImage("My Window", colourImage); cvWaitKey(10); cvWriteFrame(outputMovie, colourImage); } cvReleaseImage(&temp); cvReleaseImage(&difference); cvReleaseImage(&greyImage); cvReleaseImage(&movingAverage); cvDestroyWindow("My Window"); cvReleaseCapture(&input); cvReleaseVideoWriter(&outputMovie);return 0;}
至少它现在可以正确编译…但在运行时遇到了一些错误…我现在没有调试器来跟踪它…你可以试试…我也在尝试…