OpenCV图像识别、移动侦测、边缘检测实现及 cvCopy()和cvCloneImage()的区别
文章转自王牌软件
站长推荐:NSetup一键部署软件
一键式完成美化安装包制作,自动增量升级,数据统计,数字签名。应对各种复杂场景,脚本模块化拆分,常规复杂的脚本代码,图形化设置。无需专业的研发经验,轻松完成项目部署。(www.nsetup.cn)
只回答业务咨询
站长推荐:NSetup一键部署软件
一键式完成美化安装包制作,自动增量升级,数据统计,数字签名。应对各种复杂场景,脚本模块化拆分,常规复杂的脚本代码,图形化设置。无需专业的研发经验,轻松完成项目部署。(www.nsetup.cn)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 |
#include <stdio.h> #include <time.h> #include <cv.h> #include <cxcore.h> #include <highgui.h> int main( int argc, char** argv ) { //声明IplImage指针 IplImage* pFrame = NULL; //pFrame为视频截取的一帧 IplImage* pFrame1 = NULL; //第一帧 IplImage* pFrame2 = NULL;//第二帧 IplImage* pFrame3 = NULL;//第三帧 IplImage* pFrImg = NULL; //pFrImg为当前帧的灰度图 IplImage* pBkImg = NULL; //pBkImg为当前背景的灰度图 IplImage* pBkImgTran = NULL;//pBkImgTran为当前背景处理过的图像 IplImage* pFrImgTran = NULL;//pFrImgTran为当前背景处理过的图像 CvMat* pFrameMat = NULL; //pFrameMat为当前灰度矩阵 CvMat* pFrMat = NULL; //pFrMat为当前前景图矩阵,当前帧减去背景图 CvMat* bg1 = NULL; CvMat* bg2 = NULL; CvMat* bg3 = NULL; CvMat* pFrMatB = NULL; //pFrMatB为二值化(0,1)的前景图 CvMat* pBkMat = NULL; CvMat* pZeroMat = NULL; //用于计算bg1 - bg2 的值 CvMat* pZeroMatB = NULL;//用于计算 pZeroMat阈值化后来判断有多少个零的临时矩阵 CvCapture* pCapture = NULL; int warningNum = 0; //检测到有异物入侵的次数 int nFrmNum = 0;//帧计数 int status = 0; //状态标志位 //创建窗口 cvNamedWindow("video", 1); cvNamedWindow("background",1);//背景 cvNamedWindow("foreground",1);//前景 //使窗口有序排列 cvMoveWindow("video", 30, 0); cvMoveWindow("background", 360, 0); cvMoveWindow("foreground", 690, 0); if ( argc > 2 ) { fprintf(stderr, "Usage: bkgrd [video_file_name]\n"); return -1; } //打开摄像头 从摄像头取出码流可以使海康、大唐等网络或者模拟摄像头 if (argc ==1) if ( !(pCapture = cvCaptureFromCAM(-1))) { fprintf(stderr, "Can not open camera.\n"); return -2; } //打开视频文件 if (argc == 2) if ( !(pCapture = cvCaptureFromFile(argv[1]))) { fprintf(stderr, "Can not open video file %s\n", argv[1]); return -2; } //开始计时 time_t start,end; time(&start); //time() 返回从1970年1月1号00:00:00开始以来到现在的秒数(有10为数字)。 printf("%d\n",start); //逐帧读取视频 while (pFrame = cvQueryFrame( pCapture )) { nFrmNum++; //如果是第一帧,需要申请内存,并初始化 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); pBkImgTran = cvCreateImage(cvSize(pFrame->width,pFrame->height), IPL_DEPTH_8U,1); pFrImgTran = cvCreateImage(cvSize(pFrame->width,pFrame->height), IPL_DEPTH_8U,1); pBkMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1); pZeroMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1); pFrMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1); pFrMatB = cvCreateMat(pFrame->height, pFrame->width, CV_8UC1); pZeroMatB = cvCreateMat(pFrame->height, pFrame->width, CV_8UC1); pFrameMat = cvCreateMat(pFrame->height, pFrame->width, CV_32FC1); cvZero(pZeroMat); //转化成单通道图像再处理 cvCvtColor(pFrame, pBkImg, CV_BGR2GRAY); //转换为矩阵 cvConvert(pFrImg, pBkMat); } else /* 不是第一帧的就这样处理 */ { //pFrImg为当前帧的灰度图 cvCvtColor(pFrame, pFrImg, CV_BGR2GRAY); //pFrameMat为当前灰度矩阵 cvConvert(pFrImg, pFrameMat); //pFrMat为前景图矩阵,当前帧减去背景图 cvAbsDiff(pFrameMat, pBkMat, pFrMat); //pFrMatB为二值化(0,1)的前景图 cvThreshold(pFrMat,pFrMatB, 60, 1, CV_THRESH_BINARY); //将图像矩阵转化为图像格式,用以显示 cvConvert(pBkMat, pBkImgTran); cvConvert(pFrMat, pFrImgTran); //显示图像 cvShowImage("video", pFrame); cvShowImage("background", pBkImgTran); //显示背景 cvShowImage("foreground", pFrImgTran); //显示前景 //以上是每抓取一帧都要做的工作,下面进行危险检测 if (cvCountNonZero(pFrMatB) > 10000 && status == 0) //表示是第一帧的异物大于1W个像数点 {/* 则需要将当前帧存储为第一帧 */ pFrame1 = cvCloneImage(pFrame); bg1 = cvCloneMat(pFrMat); status = 1; //继续采集第2帧 } else if (cvCountNonZero(pFrMatB) < 10000 && status == 1) // 表示第一帧的异物大于1W个像数点,而第二帧没有,则报警 { printf("NO.%d warning!!!!\n\n",warningNum++); status = 0; } else if (cvCountNonZero(pFrMatB) > 10000 && status == 1)// 表示第一帧和第二帧的异物都大于1W个像数点 { pFrame2 = cvCloneImage(pFrame); bg2 = cvCloneMat(pFrMat); cvAbsDiff(bg1, bg2, pZeroMat); cvThreshold(pZeroMat,pZeroMatB, 20, 1, CV_THRESH_BINARY); if (cvCountNonZero(pZeroMatB) > 3000 ) //表示他们不连续,这样的话要报警 { printf("NO.%d warning!!!!\n\n",warningNum++); status = 0; } else { status = 2; //继续采集第3帧 } } else if (cvCountNonZero(pFrMatB) < 10000 && status == 2)//表示第一帧和第二帧的异物都大于1W个像数点,而第三帧没有 { //报警 printf("NO.%d warning!!!!\n\n",warningNum++); status = 0; } else if (cvCountNonZero(pFrMatB) > 10000 && status == 2)//表示连续3帧的异物都大于1W个像数点 { pFrame3 = cvCloneImage(pFrame); bg3 = cvCloneMat(pFrMat); cvAbsDiff(bg2, bg3, pZeroMat); cvThreshold(pZeroMat,pZeroMatB, 20, 1, CV_THRESH_BINARY); if (cvCountNonZero(pZeroMatB) > 3000 ) //表示他们不连续,这样的话要报警 { printf("NO.%d warning!!!!\n\n",warningNum++); } else //表示bg2,bg3连续 { cvReleaseMat(&pBkMat); pBkMat = cvCloneMat(pFrameMat); //更新背景 } status = 0; //进入下一次采集过程 } //如果有按键事件,则跳出循环 //此等待也为cvShowImage函数提供时间完成显示 //等待时间可以根据CPU速度调整 if ( cvWaitKey(2) >= 0 ) break; }/* The End of the else */ }/* The End of th while */ //销毁窗口 cvDestroyWindow("video"); cvDestroyWindow("background"); cvDestroyWindow("foreground"); //释放图像和矩阵 cvReleaseImage(&pFrImg); cvReleaseImage(&pBkImg); cvReleaseMat(&pFrameMat); cvReleaseMat(&pFrMat); cvReleaseMat(&pBkMat); cvReleaseCapture(&pCapture); return 0; } 所研究的运动检测和背景更新方法实现的步骤如下: (1)开辟静态内存,对图像进行初始化准备采集; (2)采集图像,定义参数k,作为图像序列计数。采集第1幅图像时,则根据第一帧的大小信息进行矩阵、图像的初始化,并且将第一帧图像进行灰度化处理,并转化为矩阵,作为背景图像及矩阵;如果k不等于1则把当前帧进行灰度化处理,并转化为矩阵,作为当前帧的图像及矩阵。用当前帧的图像矩阵和背景帧的图像矩阵做差算出前景图矩阵并对其进行二值化以便计算它与背景帧差别较大的像素个数,也就是二值化后零的个数。 当第一帧的异物大于1W个像数点则需要将当前帧存储为第一帧,并且将系统的状态转为1——采集第二帧; 第一帧和第二帧的异物都大于1W个像数点时,将当前帧存储为第二帧,通过判断第一帧和第二帧的差值来确定两帧是否连续,若连续则将系统状态转为2——采集第三帧,若不连续则报警,并把系统状态转为0——采集背景帧; 当第一帧和第二帧的异物都大于1W个像数点,而第三帧没有时则报警; 若连续3帧的异物都大于1W个像数点时,将当前帧存储为第三帧,通过判断第二帧和第三帧的差值来确定两帧是否连续,若连续则将更新背景,若不连续则报警。然后把系统状态转为0——采集背景帧。 注意其中有一个0-1-2-0....的状态机。 cvCopy的原型是: void cvCopy( const CvArr* src, CvArr* dst, const CvArr* mask=NULL ); 在使用这个函数之前,你必须用cvCreateImage()一类的函数先开一段内存,然后传递给dst。cvCopy会把src中的数据复制到dst的内存中。 cvCloneImage的原型是: IplImage* cvCloneImage( const IplImage* image ); 在使用函数之前,不用开辟内存。该函数会自己开一段内存,然后复制好image里面的数据,然后把这段内存中的数据返回给你。 clone是把所有的都复制过来,也就是说不论你是否设置Roi,Coi等影响copy的参数,clone都会原封不动的克隆过来。 copy就不一样,只会复制ROI区域等。 |
学习日记,兼职软件设计,软件修改,毕业设计。
本文出自 学习日记,转载时请注明出处及相应链接。
本文永久链接: https://www.softwareace.cn/?p=399