前段时间做了一个关于视频检测的小项目。目的是检测一段视频中灰色球员的运动和统计,之前学的图像处理都是线检测部分,这次涉及到视频过渡其实也没有想象中那么难。
这里还是采用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的童鞋应该就可以很快识别图中的球员,但对于大部分童鞋来说可能还是有点问题,效果待改进。