1、镜头边界检测 0101概念介绍三种方法实验小结020203030404050501概念介绍基本概念视频由一个个镜头所组成,镜头是时间上连续的若干幅帧图像组成的片段。当镜头发生转变时,会产生一些明显的变化,镜头边界检测依据这些变化来判断镜头是否发生转变。镜头发生转变时的边界帧,也称关键帧。镜头镜头镜头边界检测镜头边界检测基本概念镜头边界检测的基础是两个连续镜头的内容有较大的不同性,因此可以用定量的方法来确定帧序列之间的差别;如果这种差别超出了给定的阈值,就可以提取出镜头的边界(关键帧)关键帧短片截图的关键帧02三种方法 一帧本质就是一张图片,因此衡量两帧之间变化本质就是衡量两张图片的区别。在KN
2、N算法中衡量两张图片之间相似度就是图片对应像素相减之和,将其累加,值最小的即最接近的两张图片。连续帧相减法中,我们同样使用这个指标来评价两张图片的近似度,一旦区别大到一定地步则认为该两帧是镜头边界。连续帧相减算法原理:计算相邻两帧像素变化的数目。当超过设定的阈值时,即找到镜头的边界 缺点:对摄像机运动敏感,如放缩、平移,往往较小的物体运动会造成很大的帧间差,从而容易导致误检测解决办法:通过滤波器的使用来降低。在比较一帧的每个像素前,用它的邻近区域的平均值来代替,这也过滤了输入图像的一些噪声。连续帧相减图片演示相邻连续帧图片演示直方图相减代码算法原理:统计相邻两帧中所有像素在不同灰度(颜色)上的
3、分布差异,当差异的累加值超过阈值T时,即检测到镜头边界 优点:对对象运动不敏感,因为直方图忽略了帧内的空间变化 缺点:可能两个图像有类似的直方图但却是完全不同的内容。然而,这种事件的概率是足够低图片演示相邻两个帧图像帧图像灰度图灰度图直方图时空切片代码切片就是从连续的视频图像序列的同一个位置提取出的一行(列)像素组合而成的一幅二维图像。如果将视频看作是一个(x,y,t)三维图像序列,其中(x,y)为图像维,t为时间维,则视频的时空切片可以看作是由时间维与图像维构成的一幅二维图像。时空切片切片颜色和纹理纹理中包含有对应视频的大量信息,包括镜头切变点、摄像机的运动方式等因为单个镜头内部的视频帧在时
4、间、空间和图像结构上是连续的,在时空切片上的表现就是颜色和纹理空间上的连续性。镜头发生切换时,视频数据会跟着发生一系列的变化,表现在颜色差异突然增大、运动的不连续等,时空切片上的颜色和纹理也会表现出明显的不连续现象。03实验连续帧相减代码实现直方图相减代码实现/imhist(i);直接显示图像i的灰度直方图;直方图相减代码实现直方图相减少关键帧时空切片代码实现int main(int argc,char*argv)/void cutColSlide(CvMat*,CvMat*,int,int);/垂直切片void cutRowSlide(CvMat*,CvMat*,int,int);/水平切片
5、int i;int nFrmNum=0;int totalFrmNum;/总帧数char*videofile=G:/Makoto.mkv;/声明IplImage指针IplImage*pFrame=NULL;/视频帧/IplImage*pSlImg_col;IplImage*pSlImg_row;/水平切片图像CvMat*pFrameMat=NULL;/视频帧数据矩阵CvMat*pFrMat_r=NULL;/前景数据CvMat*pFrMat_g=NULL;CvMat*pFrMat_b=NULL;/CvMat*pSlMat_col;CvMat*pSlMat_row;/CvMat*pSlMat_co
6、l_rCOL_NUM+1;/垂直切片数据矩阵CvMat*pSlMat_row_rROW_NUM+1;/水平切片数据矩阵/CvMat*pSlMat_col_gCOL_NUM+1;/垂直切片数据矩阵CvMat*pSlMat_row_gROW_NUM+1;/水平切片数据矩阵/CvMat*pSlMat_col_bCOL_NUM+1;/垂直切片数据矩阵CvMat*pSlMat_row_bROW_NUM+1;/水平切片数据矩阵CvCapture*pCapture=NULL;/读取视频数据的指针char filename50;时空切片代码实现/打开视频文件if(!(pCapture=cvCaptureFro
7、mFile(videofile)fprintf(stderr,Can not open video file%sn,videofile);return-2;/printf(Start to reading Video!And you have to be patient!n);/逐帧读取视频while(pFrame=cvQueryFrame(pCapture)nFrmNum+;/如果是第一帧,需要申请内存,并初始化if(nFrmNum=1)totalFrmNum=(int)cvGetCaptureProperty(pCapture,CV_CAP_PROP_FRAME_COUNT);/获取视频文
8、件总帧数/创建切片初始矩阵pSlImg_row=cvCreateImage(cvSize(pFrame-width,totalFrmNum),IPL_DEPTH_8U,3);pSlMat_row=cvCreateMat(totalFrmNum,pFrame-width,CV_32FC3);for(i=0;i width,CV_32FC1);pSlMat_row_gi=cvCreateMat(totalFrmNum,pFrame-width,CV_32FC1);pSlMat_row_bi=cvCreateMat(totalFrmNum,pFrame-width,CV_32FC1);时空切片代码实
9、现/初始化并分配图像空间和矩阵空间pFrMat_r=cvCreateMat(pFrame-height,pFrame-width,CV_32FC1);pFrMat_g=cvCreateMat(pFrame-height,pFrame-width,CV_32FC1);pFrMat_b=cvCreateMat(pFrame-height,pFrame-width,CV_32FC1);pFrameMat=cvCreateMat(pFrame-height,pFrame-width,CV_32FC3);/转化成单通道图像再处理cvConvert(pFrame,pFrameMat);cvSmooth(p
10、FrameMat,pFrameMat);cvSplit(pFrameMat,pFrMat_r,pFrMat_g,pFrMat_b,NULL);/切片for(i=0;i height/ROW_NUM),nFrmNum);cutRowSlide(pFrMat_g,pSlMat_row_gi,i*(int(pFrame-height/ROW_NUM),nFrmNum);cutRowSlide(pFrMat_b,pSlMat_row_bi,i*(int(pFrame-height/ROW_NUM),nFrmNum);时空切片代码实现/不是第一帧,正常处理elsecvConvert(pFrame,pFr
11、ameMat);cvSmooth(pFrameMat,pFrameMat);cvSplit(pFrameMat,pFrMat_r,pFrMat_g,pFrMat_b,NULL);/切片for(i=0;i height/ROW_NUM),nFrmNum);cutRowSlide(pFrMat_g,pSlMat_row_gi,i*(int(pFrame-height/ROW_NUM),nFrmNum);cutRowSlide(pFrMat_b,pSlMat_row_bi,i*(int(pFrame-height/ROW_NUM),nFrmNum);/printf(Reading Done!n);p
12、rintf(Number of frames:%d.n,totalFrmNum);/cvReleaseImage(&pFrame);cvReleaseMat(&pFrameMat);cvReleaseMat(&pFrMat_r);cvReleaseMat(&pFrMat_g);cvReleaseMat(&pFrMat_b);cvReleaseCapture(&pCapture);printf(Saven);时空切片代码实现/保存切片图像for(i=0;i=ROW_NUM;i+)cvMerge(pSlMat_row_ri,pSlMat_row_gi,pSlMat_row_bi,NULL,pSlM
13、at_row);cvConvert(pSlMat_row,pSlImg_row);sprintf(filename,G:/1.bmp,i);cvSaveImage(filename,pSlImg_row);/释放图像和矩阵cvReleaseImage(&pSlImg_row);cvReleaseMat(&pSlMat_row);for(i=0;i width,CV_32FC1);/初始化if(row_ind=pFrameMat-height)row_ind-;cvGetRow(pFrameMat,temp_row,row_ind);/从当前帧中提取出第row_ind列for(int i=0;i
14、width;i+)/将提取出的行添加到切片cvSet2D(pSlMat_row,nFrmNum-1,i,cvScalar(float*)(temp_row-data.ptr)i);/图像切片行坐标/nFrmNumcvReleaseMat(&temp_row);时空切片代码实现int main()const char*pstrImageName=G:/1.bmp;const char*pstrWindowsTitle=1.bmp;/从文件中读取图像 IplImage*pImage=cvLoadImage(pstrImageName,CV_LOAD_IMAGE_UNCHANGED);CvMat*M
15、at_src=cvCreateMat(pImage-height,pImage-width,CV_32FC3);cvConvert(pImage,Mat_src);/将iplImage数据转化为矩阵,以便计算Detect_row(Mat_src,NULL);cvConvert(Mat_src,pImage);/将矩阵数据转化为iplImage,以便显示cvNamedWindow(pstrWindowsTitle,CV_WINDOW_AUTOSIZE);cvShowImage(pstrWindowsTitle,pImage);cvWaitKey();cvDestroyWindow(pstrWin
16、dowsTitle);cvReleaseImage(&pImage);return 0;时空切片代码实现void Detect_row(CvMat*src,int*tagetframe)int width=src-width;int height=src-height;int v=0,sv=0;/v是第N帧的像素值,sv是第N-1帧的像素值int d=5;/(-d,d)的领域边界值list Frame_list;/c+列表,用于存放检测到的突变镜头边界int threshold=20;/threshold;人为设定的阈值,|v-sv|threshold表明两个像素差异大double pdiff
17、_rate=0.50;/差异率;人为设定,在(-d,d)中差异点的比例;CvMat*Mat_row_r=cvCreateMat(height,width,CV_32FC1);/创建R通道矩阵用于存放R通道像素值,注意CV_32FC1的含义CvMat*Mat_row_g=cvCreateMat(height,width,CV_32FC1);CvMat*Mat_row_b=cvCreateMat(height,width,CV_32FC1);cvSplit(src,Mat_row_b,Mat_row_g,Mat_row_r,NULL);/将3通道矩阵src的数据分别放入r.g.b三个矩阵中for(
18、int j=1;j height;j+)int pdiff_num=0;/一行中检测到差异像素点个数for(int i=0;i width;i+)v=cvmGet(Mat_row_r,j,i);/取像素(i,j)的值int count=0;/(-d,d)范围内的统计double diff_rate=0;/差异率=num_diff/count;见论文图3int num_diff=0;/差异点个数时空切片代码实现for(int k=-d;k 0&i+k threshold)/|v-sv|threshold表明两个像素差异大num_diff+;/像素相差大于阈值的个数diff_rate=1.0*nu
19、m_diff/count;/差异率=num_diff/count;注意乘以1.0/printf(diff_rate=%f,num_diff=%d,count=%dn,diff_rate,num_diff,count);if(diff_rate pdiff_rate)/当该点差异率大于设定值pdiff_ratepdiff_num+;/一行中差异点个数/printf(%d,%dn,pdiff_num,j);if(pdiff_num width/3)/一行中差异点个数 width/3;width/3是人为设定的值printf(pdiff_num=%d,Frame=%dn,pdiff_num,j);F
20、rame_list.push_back(j);/将检测到的突变帧号存放到列表中时空切片代码实现list:iterator j;for(j=Frame_list.begin();j!=Frame_list.end();+j)/遍历列表for(int i=0;i width;i+)cvmSet(Mat_row_b,*j,i,0);/将突变帧标红,即src的第*j行标红cvmSet(Mat_row_g,*j,i,0);cvmSet(Mat_row_r,*j,i,255);cvMerge(Mat_row_b,Mat_row_g,Mat_row_r,NULL,src);/将标红后的数据合并成3通道的矩阵04小结 本实验对镜头边界检测方法进行了探讨和研究,提取视频帧的特征,然后计算视频帧之间的时间特征值的差分,来衡量视频帧的相似度。最后使用基于阈值的判别方法,检测视频镜头的边界。我们可以在解码过程中获取视频帧对应的BMP图像,来判断该视频镜头边界检测实验的准确性。镜头边界检测的关键是通过利用合适的内容转换检测方法、合理的设置阈值,发现帧序列的内容变换点。三种方法较为简单,现有算法的检测效果较为理想。小结THANKS!