前段时间做了一个关于视频检测的小项目。目的是检测一段视频中灰色球员的运动和统计,之前学的图像处理都是线检测部分,这次涉及到视频过渡其实也没有想象中那么难。
这里还是采用opencv1.0来写的程序,以后要用Mat来写啦。贴上代码。效果不是太好。
#include <stdio.h>
#include <cv.h>
#include <cxcore.h>
#include <highgui.h>
using namespace std;
using namespace cv;
int main( int argc, char** argv )
{
//uchar table[256];
IplImage* pFrame = NULL;
IplImage* pFrImg = NULL;
IplImage* pBkImg = NULL;//背景RGB,选用120到175灰度级
IplImage* pBkcanny = NULL;
CvMemStorage *storage = cvCreateMemStorage();
Mat pFrameMat ,pFrMat ,pBkMat;
CvCapture* pCapture = NULL;
pCapture = cvCaptureFromFile("NBA.mp4"); //读取视频
int nFrmNum = 0;
//创建窗口
cvNamedWindow("video", 1);
//使窗口有序排列
cvMoveWindow("video", 30, 0);
if( argc > 2 )
{
fprintf(stderr, "Usage: bkgrd [video_file_name]/n");
return -1;
}
//打开视频文件
if(argc == 2)
if( !(pCapture = cvCaptureFromFile("NBA.mp4")))
{
fprintf(stderr, "Can not open video file %s/n", "NBA.mp4");
return -2;
}
//逐帧读取视频
cvSetCaptureProperty(pCapture, CV_CAP_PROP_POS_FRAMES, (double)1); //定位到帧,经检测 只有帧定位较为精确
while(pFrame = cvQueryFrame( pCapture )) //抓取并返回帧,不能直接处理帧
{
nFrmNum++;
//如果是第一帧,需要申请内存并初始化
//cout<<nFrmNum<<endl;
if(nFrmNum == 1)
{
pBkImg = cvCreateImage(cvSize(pFrame->width, pFrame->height), IPL_DEPTH_8U,1);
pFrImg = cvCreateImage(cvSize(pFrame->width, pFrame->height), IPL_DEPTH_8U,1);
pBkMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1); //建立矩阵
pFrMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1);
pFrameMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1);
//cvCvtColor(pFrame, pBkImg, CV_BGR2GRAY); //彩色图转换成灰度图像
//cvCvtColor(pFrame, pFrImg, CV_BGR2GRAY);
}
else
{
cvSmooth(pFrame, pFrame, CV_GAUSSIAN, 3, 3); //高斯平滑
//transpose(pFrMat,pp);IplImage转Mat便于操作,但是会带来额外的地址操作,花了大量时间后还是弃用
// 遍历筛选需要像素部分,对感兴趣区域操作
//uchar * p = pFrMat.data; //内置指针
for (int i = 0; i <pFrame->height; i++)
{
for (int j = 0; j <pFrame->width; j++)
{
//间接访问,设置图片BGR
CvScalar s=cvGet2D(pFrame,i,j); //其中i代表height;j代表width。
if(s.val[0]>190) //去蓝色
{
if((s.val[1]>60)&&(s.val[1]<170)&&(s.val[2]>60)&&(s.val[2]<170))
s.val[0]=s.val[1]=s.val[2]=0;
else
s.val[0]=s.val[1]=s.val[2]=255;
}else{
if(((s.val[2]<110)||(s.val[2]>130))&&((s.val[1]<110)||(s.val[1]>130)) ) //去红色
s.val[0]=s.val[1]=s.val[2]=0;
else
s.val[0]=s.val[1]=s.val[2]=255;//灰色球员进行提取
}
cvSet2D(pFrame,i,j,s);
}
}
//写一个边缘直线检测函数canny,去除边界以外的区域,可以滤波掉较小的部分(观众席)
}
//双线程同时读写一个变量出问题?
//cvCvtColor(pFrame, pFrImg, CV_BGR2GRAY); //处理灰度图像pFrImg就要用另一个形式。这里直接操作三通道
// 进行形态学滤波,去掉噪音
//cvErode(pFrame, pFrame, 0, 1);
//cvDilate(pFrame, pFrame, 0, 1);
//canny检测,出现空间不足的错误?
//pBkcanny = cvCreateImage(cvSize(pFrame->width, pFrame->height), IPL_DEPTH_8U,3);
//cvCanny(pFrImg,pBkImg,50,200,3);
//霍夫检测直线
//cvHoughLines2(pBkImg,storage,1,CV_PI/180,80,50,10);
//cvCvtColor(pBkImg, pBkcanny, CV_GRAY2BGR);//单通道转三通道
cvSmooth(pFrame, pFrame, CV_GAUSSIAN, 5, 5); //高斯平滑
cvShowImage("video",pFrame);
//此等待也为cvShowImage函数提供时间完成显示
if( cvWaitKey(2) >= 0 )
break;
}
//销毁窗口,释放图像和矩阵
cvDestroyWindow("video");
cvReleaseImage(&pFrImg);
cvReleaseImage(&pBkImg);
cvReleaseImage(&pFrame);
cvReleaseImage(&pBkcanny);
cvReleaseMemStorage(&storage);
pFrameMat.release();
pFrMat.release();
pBkMat.release();
cvReleaseCapture(&pCapture);
return 0;
}
效果图:
熟悉NBA的童鞋应该就可以很快识别图中的球员,但对于大部分童鞋来说可能还是有点问题,效果待改进。