opencv视频处理和检测学习总结
生活随笔
收集整理的這篇文章主要介紹了
opencv视频处理和检测学习总结
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
基于opencv的視頻處理——基礎數據結構
? ?在一個封裝的還算比較好的庫中,一般都不會直接采用那些基本的數據結構像char, int 之類,一是
不具有可讀性,二是不方便修改移植。通常是通過typedef 來改變。下面介紹opencv中基礎數據結構。
? ? ?先介紹點,CvPoint, CvPoint2D32f, CvPoint3D32f,下面給出原型。
二維坐標系下的點,類型為整型?
typedef struct CvPoint
{
? int x; /* X坐標, 通常以0為基點 */
? int y; /* y坐標, 通常以0為基點 */
}
CvPoint;
二維坐標下的點,類型為浮點?
typedef struct CvPoint2D32f
{
? float x; /* X坐標, 通常以0為基點*/
? float y; /* Y坐標, 通常以0為基點*/
}
CvPoint2D32f;
三維坐標下的點,類型為浮點?
typedef struct CvPoint3D32f
{
? float x; /* x-坐標, 通常基于0 */
? float y; /* y-坐標, 通常基于0 */
? float z; /* z-坐標, 通常基于0 */
}
CvPoint3D32f;
? ??
? ? 大家很明顯可以看出來,這些點還是由基本的數據類型構成的。下面再順便提一下相應類型的構造函數
CvPoint 型
inline CvPoint cvPoint( int x, int y );
CvPoint2D32f型
inline CvPoint2D32f cvPoint2D32f( double x, double y );
CvPoint3D32f型
inline CvPoint3D32f cvPoint3D32f( double x, double y, double z );
下面再介紹幾個簡單的
CvSize
矩形框大小,以像素為精度
typedef struct CvSize
{
? int width; /* 矩形寬 */
? int height; /* 矩形高 */
}
CvSize;
CvSize2D32f
以亞像素精度標量矩形框大小
typedef struct CvSize2D32f
{
? ?float width; /* 矩形寬 */
? ?float height; /* 矩形高 */
}
CvSize2D32f;
CvRect
矩形框的偏移和大小
{
? int x; /* 方形的最左角的x-坐標 */
? int y; /* 方形的最上或者最下角的y-坐標 */
? int width; /* 寬 */
? int height; /* 高 */
}
CvRect;
CvScalar
可存放在1-,2-,3-,4-TUPLE類型的捆綁數據的容器
typedef struct CvScalar
{
? double val[4]
}
CvScalar;
? ??
? ? 具體用法會在后續文章中說到,
? ? 現在介紹點重要的
IplImage
IPL 圖像頭
typedef struct _IplImage
? ? {
? ? ? ? int nSize; /* IplImage大小,=sizeof(IplImage)*/
? ? ? ? int ID; /* 版本 (=0)*/
? ? ? ? int nChannels; /* 大多數OPENCV函數支持1,2,3 或 4 個通道 */
? ? ? ? int alphaChannel; /* 被OpenCV忽略 */
? ? ? ? int depth; /* 像素的位深度: IPL_DEPTH_8U, IPL_DEPTH_8S, IPL_DEPTH_16U,IPL_DEPTH_16S,?
IPL_DEPTH_32S, IPL_DEPTH_32F and IPL_DEPTH_64F 可支持 */
? ? ? ? char colorModel[4]; /* 被OpenCV忽略 */
? ? ? ? char channelSeq[4]; /* 被OpenCV忽略 */
? ? ? ? int dataOrder; /* 0 - 交叉存取顏色通道,對三通道RGB圖像,像素存儲順序為BGR BGR BGR?
... BGR;1 - 分開的顏色通道,對三通道RGB圖像,像素存儲順序為RRR...R GGG...G BBB...B。
cvCreateImage只能創建交叉存取圖像 */
? ? ? ? int origin; /* 0 - 頂—左結構, 1 - 底—左結構 (Windows bitmaps 風格) */
? ? ? ? int align; /* 圖像行排列 (4 or 8). OpenCV 忽略它,使用 widthStep 代替 */
? ? ? ? int width; /* 圖像寬像素數 */
? ? ? ? int height; /* 圖像高像素數*/
? ? ? ? struct _IplROI *roi;/* 圖像感興趣區域. 當該值非空只對該區域進行處理 */
? ? ? ? struct _IplImage *maskROI; /* 在 OpenCV中必須置NULL */
? ? ? ? void *imageId; /* 同上*/
? ? ? ? struct _IplTileInfo *tileInfo; /*同上*/
? ? ? ? int imageSize; /* 圖像數據大小(在交叉存取格式下imageSize=image->height*image-
>widthStep),單位字節*/
? ? ? ? char *imageData; /* 指向排列的圖像數據 */
? ? ? ? int widthStep; /* 排列的圖像行大小,以字節為單位 */
? ? ? ? int BorderMode[4]; /* 邊際結束模式, 被OpenCV忽略 */
? ? ? ? int BorderConst[4]; /* 同上 */
? ? ? ? char *imageDataOrigin; /* 指針指向一個不同的圖像數據結構(不是必須排列的),是為了糾正圖像內存分配準備的 */
? ? }
? ? IplImage;
IplImage結構來自于 Intel Image Processing Library(是其本身所具有的)。OpenCV 只支持其中的一個子集:
? ? * alphaChannel 在OpenCV中被忽略。
? ? * colorModel 和channelSeq 被OpenCV忽略。OpenCV顏色轉換的唯一函數 cvCvtColor把原圖像的顏
色空間的目標圖像的顏色空間作為一個參數。
? ? * dataOrder 必須是IPL_DATA_ORDER_PIXEL (顏色通道是交叉存取),然而平面圖像的被選擇通道可
以被處理,就像COI(感興趣的通道)被設置過一樣。
? ? * align 是被OpenCV忽略的,而用 widthStep 去訪問后繼的圖像行。
? ? * 不支持maskROI 。處理MASK的函數把他當作一個分離的參數。MASK在 OpenCV 里是 8-bit,然而在?
IPL他是 1-bit。
? ? * tileInfo 不支持。
? ? * BorderMode和BorderConst是不支持的。每個 OpenCV 函數處理像素的鄰近的像素,通常使用單一的固定代碼邊際模式。?
除了上述限制,OpenCV處理ROI有不同的要求。要求原圖像和目標圖像的尺寸或 ROI的尺寸必須(根據不同的操作,
例如cvPyrDown 目標圖像的寬(高)必須等于原圖像的寬(高)除以2 ±1)精確匹配,而IPL
處理交叉區域,如圖像的大小或ROI大小可能是完全獨立的。? ? 這是一個很重要的數據結構,處理圖像時傳入的就是IplImage *Img. 對于初學者來說,首先要關注
的是成員width, height, widthstep和imageDate,比如說做一個遍歷的話
int i, j;
char *data = NULL;
for(i=0; i<Img->width; i++)
{
? ?for(j=0; j<Img->height; j++)
? {
? ? ? ?data = Img->imageData + i*widthStep + j; ?//取圖片相應點的數據,要知道圖片的存儲是以
一個矩陣的形式
? ? ? ?statement
? }
}
最后還有一個比較重要的
CvMat
多通道矩陣
typedef struct CvMat
{
? int type; /* CvMat 標識 (CV_MAT_MAGIC_VAL), 元素類型和標記 */
? int step; /* 以字節為單位的行數據長度*/
? int* refcount; /* 數據引用計數 */
? union
? {
? ? uchar* ptr;
? ? short* s;
? ? int* i;
? ? float* fl;
? ? double* db;
? } data; /* data 指針 */
? #ifdef __cplusplus
? union
? ?{
? ? ?int rows;
? ? ?int height;
? ?};
? union
? ?{
? ? ?int cols;
? ? ?int width;
? ?};
? #else
? ?int rows; /* 行數 */
? ?int cols; /* 列數*/
? #endif
} CvMat;
========
OpenCV成長之路 視頻的處理
視頻中包含的信息量要遠遠大于圖片,對視頻的處理分析也越來越成為計算機視覺的主流,而本質上視頻是由一幀幀的圖像組成,所以視頻處理最終還是要歸結于圖像處理,但在視頻處理中,有更多的時間維的
信息可以利用。本文主要介紹OpenCV在處理視頻時的一些基本函數。
一、視頻幀的讀取
OpenCV為視頻的讀入提供了一個類VideoCapture,下面我們說明一下類的幾個重要的方法:
1,打開一段視頻或默認的攝像頭
有兩種方法,一種是在定義類的時候,一種是用open()方法。
VideoCapture capture("../video.avi");?
// 方法1
capture.open("../video.avi");?
// 方法2
如果把文件名換為設置ID,則可打開攝像頭,默認攝像頭為0。
2,獲取視頻幀
獲取視頻幀可以有多種方法
// 方法一
capture.read(frame);
// 方法二
capture.grab();
capture.retrieve(frame);
// 方法三
capture>>frame;
3,獲取視頻的參數
一個視頻有很多參數,比如:幀率、總幀數、尺寸、格式等,VideoCapture的get方法可以獲取大量這些參數。
double rate=capture.get(CV_CAP_PROP_FPS);?
// 獲取
long nFrame=static_cast<long>(capture.get(CV_CAP_PROP_FRAME_COUNT));?
// 獲取總幀數
更加相關的參數可以參考手冊。
4,設置視頻幀的讀取位置
VideoCapture類的set方法可以允許我們取出視頻中某個位置的幀,它有一些參數,可以按時間,也可以
按幀號,還可以按視頻長短的比例。
// 第100幀
double position=100.0;
capture.set(CV_CAP_PROP_POS_FRAMES,position);
// 第1e6毫秒
double position=1e6;
capture.set(CV_CAP_PROP_POS_MSEC,position);
// 視頻1/2位置
double position=0.5;
capture.set(CV_CAP_PROP_POS_AVI_RATIO,position);
當然,set方法僅用于取視頻幀的位置,還可以設置視頻的幀率、亮度。
下面是一個將canny邊緣檢測應用于視頻的程序:
int main()
{
? ? VideoCapture capture("../track.avi");?
? ? if(!capture.isOpened())
? ? ? ? return 1;
? ? double rate=capture.get(CV_CAP_PROP_FPS);
? ? bool stop(false);
? ? Mat frame;
?
? ? namedWindow("Canny Video");
? ? int delay=1000/rate;
?
? ? while(!stop)
? ? {
? ? ? ? if(!capture.read(frame))
? ? ? ? ? ? break;
? ? ? ? Mat result;
? ? ? ? Canny(frame,result,100,200);
? ? ? ? threshold(result,result,128,255,THRESH_BINARY);
? ? ? ? imshow("Canny Video",result);
?
? ? ? ? if(waitKey(delay)>=0)
? ? ? ? ? ? stop=true;
? ? }
? ? capture.release();
}
二、視頻的寫入
視頻的寫入與讀取類似,OpenCV中是使用VideoWriter類來實現的,這個類有幾個方法,都很簡單。除了
構造函數外,提供了open、IsOpen、write、和重載操作符<<
值得注意的是OpenCV里對視頻的編碼解碼等支持并不是很良好,所以不要希望用這個類去實現攝像頭圖像
的獲取與轉碼,有興趣的可以參考FFmpeg庫。
VideoWriter::VideoWriter(const string& filename, int fourcc, double fps, Size frameSize,?
bool isColor=true);
bool VideoWriter::open(const string& filename, int fourcc, double fps, Size frameSize, bool?
isColor=true);
上面是類的構造函數與open方法,它們的參數相同,首先指定文件名,第二個參數是編碼格式,OpenCV里
提供了很多種的編碼格式,如CV_FOURCC(‘P’,’I’,’M’,’1’)是MPEG-1格式,CV_FOURCC(‘M’,’
G’,’P’,’G’)為motion-jpeg格式。
第三個參數為幀率,第4個參數為視頻的尺寸大小。
VideoCapture capture("../track.avi");?
double rate=capture.get(CV_CAP_PROP_FPS);
Size videoSize(capture.get(CV_CAP_PROP_FRAME_WIDTH),
? ? ? ? ? ? ? ?capture.get(CV_CAP_PROP_FRAME_HEIGHT));
VideoWriter writer;
writer.open("../result.avi",CV_FOURCC('P','I','M','1'),rate, videoSize);
Mat frame;
capture>>frame;
writer<<frame;
?
========
OpenCV視頻處理相關編程總結
? ? ?高級語言自帶的播放視頻的API多是把視頻當成一個整體的文件進行讀取,但是實際上視頻文件時由
圖片按幀排列而成,中間加上時間戳,普通的這種視頻讀取方法不利用按幀進行圖像處理,然后適時播放
。譬如我們要寫一個程序,detect這個視頻中出現的某一個人,當這個人出現的時候,在視頻中把這個人
的位置畫出來。普通的視頻讀取方法無法完成這一功能。幸運的是,作為一個強大的圖像處理工具包,
OpenCV提供了一套按幀讀取的開放API,本文主要介紹OpenCV在視頻處理中常用的一些方法。
(1)按幀讀取視頻的例子程序
#include "opencv2/opencv.hpp"
#include "opencv2/core/core.hpp"
#include <opencv2\video\video.hpp>
using namespace std;
using namespace cv;
int main()
{
? ? ?// Open the video file
? ? ?cv::VideoCapture capture("F:/Output.avi");
? ? ?// check if video successfully opened
? ? ?if (!capture.isOpened())
? ? ? ? ? return 1;
? ? ?// Get the frame rate
? ? ?double rate= capture.get(CV_CAP_PROP_FPS);
? ? ?bool stop(false);
? ? ?cv::Mat frame; // current video frame
? ? ?cv::namedWindow("Extracted Frame");
? ? ?// Delay between each frame in ms
? ? ?// corresponds to video frame rate
? ? ?long frames= static_cast<long>(
? ? ?capture.get(CV_CAP_PROP_FRAME_COUNT));
? ? ?cout<<"rate="<<rate<<endl;
? ? ?cout<<"Frames="<<frames<<endl;
? ? ?int delay= 1000/rate;
? ? ?cout<<"delay="<<delay<<endl;
? ? ?// for all frames in video
? ? ?//while (!stop) {
? ? ? ? ? // // read next frame if any
? ? ? ? ? // if (!capture.read(frame))
? ? ? ? ? // break;
? ? ? ? ? // cv::imshow("Extracted Frame",frame);
? ? ? ? ? // // introduce a delay
? ? ? ? ? // // or press key to stop
? ? ? ? ? // if (cv::waitKey(delay)>=0)
? ? ? ? ? // stop= true;
? ? ?//}
? ? ?// Close the video file.
? ? ?// Not required since called by destructor
? ? ?//read the video by for-loop
? ? ?for(int i=1;i<frames;i++)
? ? ?{
? ? ? ? ? double position= double(i);
? ? ? ? ? capture.set(CV_CAP_PROP_POS_FRAMES, position);
? ? ? ? ? capture.read(frame);
? ? ? ? ? imshow("Extracted Frame",frame);
? ? ? ? ? waitKey(100);//define the dalay time
? ? ?}
? ? ?capture.release();
}
(2)在Android編程中使用OpenCV
http://underthehood.blog.51cto.com/2531780/670169
(3).hpp和.h的區別
?hpp實質上就是將.cpp的實現代碼混入.h頭文件當中,定義與實現都包含在同一文件。
(4)初始化一個矩陣
Mat img=Mat::zeros(53,21,CV_8U);//uchar類型的矩陣
(5)OpenCV與彩色圖像
int main()
{
? ? ?Mat img=imread("data/test.jpg",1);
? ? ?for(int i=0;i<img.rows;i++)
? ? ?{
? ? ? ? ? for(int j=0;j<img.cols;j++)
? ? ? ? ? {
? ? ? ? ? ? ? ?img.ptr<Point3_<uchar>>(i,j)->x=0;
? ? ? ? ? ? ? ?img.ptr<Point3_<uchar>>(i,j)->y=0;
? ? ? ? ? ? ? ?img.ptr<Point3_<uchar>>(i,j)->z=255;
? ? ? ? ? }
? ? ?}
? ? ?imshow("img",img);
? ? ?waitKey(0);
? ? ?return 0;
}
========
基于opencv的視頻處理——高斯背景建模
? ?? ? 運動檢測的一般方法
? ? 目前,運動物體檢測的問題主要分為兩類,攝像機固定和攝像機運動。對于攝像機運動的運動物體檢
測問題,比較著名的解決方案是光流法,通過求解偏微分方程求 的圖像序列的光流場,從而預測攝像機
的運動狀態。對于攝像機固定的情形,當然也可以用光流法,但是由于光流法的復雜性,往往難以實時的
計算,所以我采用高 斯背景模型。因為,在攝像機固定的情況下,背景的變化是緩慢的,而且大都是光
照,風等等的影響,通過對背景建模,對一幅給定圖像分離前景和背景,一般來 說,前景就是運動物體
,從而達到運動物體檢測的目的。
? ? 在這里我要介紹的是攝像機固定的情況,分離圖像的前景和背景,之前的想法很天真----幀差法。就
是取含有目標物體的當前幀去減背景,現在想想真的很天真,這就是沒有文化不知道害怕啊!完全沒有圖
像處理的理論基礎啊,完全不顧噪音等的影響。虧我認真的去調程序,可結果讓我咋舌阿!
? ? 然后知道了高斯背景建模的處理方法,高斯處理的還不錯,我又加了平滑處理,代碼如下
#include <stdio.h>
#include "cv.h"
#include "cxcore.h"
#include "highgui.h"
#include "cxtypes.h"
//#include "function.h"
#include "cvaux.h"
int cvSumImage(IplImage *Img)
{
? ? int sum = 0;
? ? int i, j;
? ? int width = Img->width;
? ? int height = Img->height;
? ? int step = Img->widthStep;
? ? unsigned char *data = (unsigned char*)Img->imageData;
? ? for(i=0; i<height; i++)
? ? ?for(j=0; j<width; j++)
? ? ?{
? ? ? ? ?if(data[i*step+j])?
? ? ? ? ? ? sum ++;
? ? ?}
? ??
? ? return sum;
}
int main(int argc, char **argv)
{
? ? IplImage* pFrame = NULL;
? ? IplImage* pFrImg = NULL;
? ? IplImage* pBkImg = NULL;
? ? IplImage* Img0 = NULL;
? ? IplImage* DiffImg = NULL;
? ? IplImage* SumImg = NULL;
? ? IplImage* FirstImg = NULL;
? ??
? ? CvCapture* pCapture = NULL;
? ? int nFrmNum = 0;
? ? cvNamedWindow("video", 1);
? ? cvNamedWindow("background", 1);
? ? cvNamedWindow("foreground", 1);
? ? cvMoveWindow("video", 30, 0);
? ? cvMoveWindow("background", 360, 0);
? ? cvMoveWindow("foreground", 690, 0);
? ? if(argc > 3)
? ? {
? ? ? ? fprintf(stderr, "Usage: bkgrd [video_file_name\n]");
? ? ? ? return -1;
? ? }
? ? if(argc == 2)
? ? ?if( !(pCapture = cvCaptureFromFile(argv[1])))
? ? ?{
? ? ? ? ?fprintf(stderr, "Can not open video file %s\n", argv[1]);
? ? ? ? ?return -1;
? ? ?}
? ? if(argc == 3)
? ? ?if( !(pCapture = cvCaptureFromCAM(-1)))
? ? ?{
? ? ? ? ?fprintf(stderr, "Can not open camera.\n");
? ? ? ? ?return -2;
? ? ?}
? ? CvGaussBGModel* bg_model = NULL;
? ? while( pFrame=cvQueryFrame( pCapture ))
? ? {
? ? ? ? nFrmNum ++;
? ? ? ? if( nFrmNum == 1)
? ? ? ? {
? ? ? ? ? ? pBkImg = cvCreateImage(cvSize(pFrame->width, pFrame->height), IPL_DEPTH_8U, 3);
? ? ? ? ? ? pFrImg = cvCreateImage(cvSize(pFrame->width, pFrame->height), IPL_DEPTH_8U, 1);
? ? ? ? ? ? FirstImg = cvCreateImage(cvSize(pFrame->width, pFrame->height), IPL_DEPTH_8U,?
1);
// ? ? ? ? ? ?cvCvtColor(pFrame, pFrImg, CV_BGR2GRAY);
// ? ? ? ? ? ?cvSaveImage("1.jpg",pFrImg);
? ? ? ? ? ? CvGaussBGStatModelParams params;
? ? ? ? ? ? params.win_size = 200;
? ? ? ? ? ? params.bg_threshold = 0.7;
? ? ? ? ? ? params.std_threshold = 2.5;
? ? ? ? ? ? params.weight_init = 0.05;
? ? ? ? ? ? params.variance_init = 30*30;
? ? ? ? ? ? params.minArea = 15.f;
? ? ? ? ? ? params.n_gauss = 5;
? ? ? ? ? ? bg_model = (CvGaussBGModel*) cvCreateGaussianBGModel(pFrame, 0);
? ? ? ? }
? ? ? ? else
? ? ? ? {
? ? ? ? ? ? int regioncount = 0;
? ? ? ? ? ? int totalNum = pFrImg->width * pFrImg->height;
// ? ? ? ? ? ?regioncount = icvUpdateGaussianBGModel(pFrame, bg_model);
? ? ? ? ? ? cvUpdateBGStatModel(pFrame, (CvBGStatModel *)bg_model);
? ? ? ? ? ? cvCopy(bg_model->foreground, pFrImg, 0);
? ? ? ? ? ? cvCopy(bg_model->background, pBkImg, 0);
? ? ? ? ? ? cvErode(pFrImg, pFrImg, NULL, 1);
? ? ? ? ? ? cvDilate(pFrImg, pFrImg, 0, 1);
? ? ? ? ? ? cvSmooth(pFrImg, pFrImg, CV_GAUSSIAN, 3, 0, 0, 0);
// ? ? ? ? ? ?cvCvtColor(pFrame, pFrImg, CV_BGR2GRAY);
// ? ? ? ? ? ?cvSaveImage("2.jpg", pFrImg);
? ? ? ? ? ? //把圖像正過來
? ? ? ? ? ? pFrImg->origin = 1;
? ? ? ? ? ? cvShowImage("video", pFrame);
? ? ? ? ? ? cvShowImage("background", pBkImg);
? ? ? ? ? ? cvShowImage("foreground", pFrImg);
// ? ? ? ? ? ?printf("number is %d\n", cvSumImage(pFrImg));
// ? ? ? 取目標幀
? ? ? ? ? ? if(nFrmNum > 10 && (double)cvSumImage(pFrImg) > 0.3*totalNum )
? ? ? ? ? ? {
? ? ? ? ? ? ? ? int first, next;
? ? ? ? ? ? ? ? first = cvSumImage(FirstImg);
? ? ? ? ? ? ? ? next = cvSumImage( pFrImg );
? ? ? ? ? ? ? ? printf("number is %d\n", next);
? ? ? ? ? ? ? ? if(next < first)
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? cvCopy(pFrImg, FirstImg, 0);
? ? ? ? ? ? }
? ? ? ? ? ? cvCopy(pFrImg, FirstImg, 0);
? ? ? ? ? ? if( cvWaitKey(2)>=0)
? ? ? ? ? ? ?break;
? ? ? ? }
? ? }
? ? printf("%d\n", pFrImg->width*pFrImg->height);
? ? cvReleaseBGStatModel((CvBGStatModel**)&bg_model);
? ??
? ? cvDestroyWindow("video");
? ? cvDestroyWindow("background");
? ? cvWaitKey(0);
? ? cvDestroyWindow("foreground");
? ? cvReleaseImage(&pFrImg);
? ? cvReleaseImage(&pBkImg);
? ? cvReleaseImage(&FirstImg);
? ? cvReleaseCapture(&pCapture);
? ? return 0;
}
========
?基于opencv的視頻處理——圖像輪廓邊緣檢測Canny算法
? ? 在數字圖像處理中有一個重要的內容就是邊緣檢測。先說下邊緣檢測的原理吧!
? ? 邊緣檢測實際上就是標記圖像中變化梯度比較大的點,這時大家應該想到倒數了。
? ? 下面附上程序,挺簡單的一個程序。具體細節以后再說
#include <stdio.h>
#include "cv.h"
#include "cxcore.h"
#include "highgui.h"
//#include "tklopencv.h"
int main(int argc, char **argv)
{
? ? int i,j;
? ? char *p = NULL;
? ? IplImage *pImg = NULL;
? ? IplImage *pCannyImg = NULL;
? ? IplImage *ReImg = NULL;
? ? if(argc == 2 && (pImg = cvLoadImage(argv[1],0)) != 0)
? ? {
? ? ? ? int width = pImg->width;
? ? ? ? int height = pImg->height;
? ? ? ? pCannyImg = cvCreateImage(cvGetSize(pImg), IPL_DEPTH_8U, 1);
? ? ? ? ReImg = cvCreateImage(cvSize(800,640), IPL_DEPTH_8U, 1);
? ? ? ? printf("%d\t%d\n", pImg->width, pImg->widthStep);
? ? ? ? cvCanny(pImg, pCannyImg, 50, 159, 3); ? ? ? ?//設定閾值并檢測
? ? ? ? cvErode(pCannyImg, pCannyImg, NULL, 1);
? ? ? ? cvDilate(pCannyImg, pCannyImg, 0, 1);
? ? ? ? cvSmooth(pCannyImg, pCannyImg, CV_GAUSSIAN, 3, 0, 0, 0);
? ? ? ? cvNamedWindow("src", 1);
? ? ? ? cvNamedWindow("canny", 1);
// ? ? ? ?cvNamedWindow("Reset", 1);
? ? ? ? cvShowImage("src", pImg);
? ? ? ? cvShowImage("canny", pCannyImg);
// ? ? ? ?cvShowImage("Reset", ReImg);
? ? ? ? cvWaitKey(0);
? ? ? ? cvDestroyWindow("src");
? ? ? ? cvDestroyWindow("canny");
// ? ? ? ?cvDestroyWindow("Reset");
? ? ? ? cvReleaseImage(&pImg);
? ? ? ? cvReleaseImage( &pCannyImg);
? ? ? ? cvReleaseImage(&ReImg);
? ? ? ? return 0;
? ? }
? ? printf("Error!\n");
? ? return -1;
}
========
OpenCV2學習筆記:視頻流讀取與處理
由于項目需要,計劃實現九路視頻拼接,因此必須熟悉OpenCV對視頻序列的處理。視頻信號處理是圖像處
理的一個延伸,所謂的視頻序列是由按一定順序進行排放的圖像組成,即幀(Frame)。在這里,主要記錄
下如何使用Qt+OpenCV讀取視頻中的每一幀,之后,在這基礎上將一些圖像處理的算法運用到每一幀上(
如使用Canny算子檢測視頻中的邊緣)。
一. 讀取視頻序列
OpenCV提供了一個簡便易用的框架以提取視頻文件和USB攝像頭中的圖像幀,如果只是單單想讀取某個視
頻,你只需要創建一個cv::VideoCapture實例,然后在循環中提取每一幀。新建一個Qt控制臺項目,直接
在main函數添加:
#include <QCoreApplication>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <QDebug>
int main(int argc, char *argv[])
{
? ? QCoreApplication a(argc, argv);
? ? // 讀取視頻流
? ? cv::VideoCapture capture("e:/BrokeGirls.mkv");
? ? // 檢測視頻是否讀取成功
? ? if (!capture.isOpened())
? ? {
? ? ? ? qDebug() << "No Input Image";
? ? ? ? return 1;
? ? }
? ? // 獲取圖像幀率
? ? double rate= capture.get(CV_CAP_PROP_FPS);
? ? bool stop(false);
? ? cv::Mat frame; // 當前視頻幀
? ? cv::namedWindow("Extracted Frame");
? ? // 每一幀之間的延遲
? ? int delay= 1000/rate;
? ? // 遍歷每一幀
? ? while (!stop)
? ? {
? ? ? ? // 嘗試讀取下一幀
? ? ? ? if (!capture.read(frame))
? ? ? ? ? ? break;
? ? ? ? cv::imshow("Extracted Frame",frame);
? ? ? ? // 引入延遲
? ? ? ? if (cv::waitKey(delay)>=0)
? ? ? ? ? ? ? ? stop= true;
? ? }
? ? ? ? return a.exec();
}
(注意:要正確打開視頻文件,計算機中必須安裝有對應的解碼器,否則cv::VideoCapture無法理解視頻
格式!)運行后,將出現一個窗口,播放選定的視頻(需要在創建cv::VideoCapture對象時指定視頻的文
件名)。
二. 處理視頻幀
為了對視頻的每一幀進行處理,這里創建自己的類VideoProcessor,其中封裝了OpenCV的視頻獲取框架,
該類允許我們指定每幀調用的處理函數。
首先,我們希望指定一個回調處理函數,每一幀中都將調用它。該函數接受一個cv::Mat對象,并輸出處
理后的cv::Mat對象,其函數簽名如下:
void processFrame(cv::Mat& img, cv::Mat& out);
作為這樣一個處理函數的例子,以下的Canny函數計算圖像的邊緣:
? ? // 對視頻的每幀做Canny算子邊緣檢測
void canny(cv::Mat& img, cv::Mat& out)?
{
? ? // 先要把每幀圖像轉化為灰度圖
? ? cv::cvtColor(img,out,CV_BGR2GRAY);
? ? // 調用Canny函數
? ? cv::Canny(out,out,100,200);
? ? // 對像素進行翻轉
? ? cv::threshold(out,out,128,255,cv::THRESH_BINARY_INV);
}
定義好一個視頻處理類,它將與一個回調函數相關聯。使用該類,可以創建一個實例,指定輸入的視頻文
件,綁定回調函數,然后開始對每一幀進行處理,要調用這個視頻處理類,只需在main函數中添加:
? ? // 定義一個視頻處理類處理視頻幀
? ? // 首先創建實例
? ? VideoProcessor processor;
? ? // 打開視頻文件
? ? processor.setInput("e:/BrokeGirls.mkv");
? ? // 聲明顯示窗口
? ? // 分別為輸入和輸出視頻
? ? processor.displayInput("Input Video");
? ? processor.displayOutput("Output Video");
? ? // 以原始幀率播放視頻
? ? processor.setDelay(1000./processor.getFrameRate());
? ? // 設置處理回調函數
? ? processor.setFrameProcessor(canny);
? ? // 開始幀處理過程
? ? processor.run();
? ? cv::waitKey();
未完待續…
========
視頻加載、處理、輸出
?一、加載播放視頻<span style="font-size:24px;">#include "stdafx.h" ?
using namespace std; ?
using namespace cv; ?
??
int main() ?
{ ? ??
? ? //下面兩種方法都可以打開視頻 ?
? ? VideoCapture capture("../1.avi"); ?
? ? /*2、VideoCapture capture;?
? ? capture.open("../1.avi");*/ ?
? ? if(!capture.isOpened()) ?
? ? ? ? return 1; ?
? ? double rate = capture.get(CV_CAP_PROP_FPS); ?
? ? bool stop(false); ?
? ? Mat frame; ?
? ? namedWindow("Extracted Frame"); ?
? ? //這個delay的單位是ms,若是秒,則delay為1/rate。 ?
? ? //rate為每秒播放的幀數 ?
? ? int delay = 1000/rate; ?
? ? //用于設置直接播放哪一幀 ?
? ? double position= 0.0; ??
? ? capture.set(CV_CAP_PROP_POS_FRAMES, position); ?
? ? while(!stop) ?
? ? { ?
? ? ? ? //以下三種方法都可以讀取視頻 ?
? ? ? ? if(!capture.read(frame)) ?
? ? ? ? ? ? break; ?
? ? ? ? /*2、capture>>frame;*/ ?
? ? ? ? /*3、capture.grab();?
? ? ? ? capture.retrieve(frame);*/ ?
? ? ? ? imshow("Extracted Frame",frame);</span><span style="font-size:24px;"> ?
? ? ? ? </span><span style="font-size:24px;">if(waitKey(delay) >= 0) ?
? ? ? ? ? ? stop = true;<span style="font-size:24px;">//<span style="color:#ff0000;">當
delay==0時,將會暫停在該幀,不再執行下去,</span><span style="color:#ff0000;">若不是0,則會等
待鍵盤的消息輸入,則結束</span></span> ?
? ? } ?
? ? //</span><span style="font-size:24px;"><span style="color:#ff0000;">關閉視頻文件,但是不
是必須的,VideoCapture構造函數會默認調用它 ?
</span> capture.release(); ?
} ?
</span> ?
?
二、對視頻讀入、處理、輸出進行的封裝
頭文件代碼:
<span style="font-size:24px;">#pragma once ?
using namespace cv; ?
class VideoProcessor ?
{ ?
private://用于打開處理視頻 ?
? ? //opencv 視頻捕捉對象 ?
? ? VideoCapture capture; ?
? ? //回調函數將調用每幀處理函數 ?
? ? void (*process)(Mat&,Mat&); ?
? ? //是否調用回調函數的開關 ?
? ? bool callIt; ?
? ? //輸入視頻的播放窗口名字 ?
? ? string windowNameInput; ?
? ? //輸入視頻的播放窗口名字 ?
? ? string windowNameOutput; ?
? ? //播放每幀之間的暫停間隔 ?
? ? int delay; ?
? ? //已處理的幀數 ?
? ? long fnumber; ?
? ? //停止在某一幀 ?
? ? long frameToStop; ?
? ? //停止處理的開關 ?
? ? bool stop; ?
? ? //存儲獲得的視頻每幀 ?
? ? Mat image; ?
public: ?
? ? //設置回調函數,用于處理幀 ?
? ? void setFrameProcessor( ?
? ? ? ? void (*frameProcessingCallback)(Mat&,Mat&)) ?
? ? { ?
? ? ? ? process = frameProcessingCallback; ?
? ? } ?
? ? //打開一個視頻文件 ?
? ? bool setInput(string filename); ?
? ? //創建一個窗口顯示輸入幀 ?
? ? void displayInput(string wn); ?
? ? //創建一個窗口顯示輸出幀 ?
? ? void displayOutput(string wn); ?
? ? //不顯示幀 ?
? ? void dontDisplay(void); ?
? ? //抓取或處理幀序列 ?
? ? void run(void); ?
? ? //捕捉設備是否打開 ?
? ? bool isOpened(){ return capture.isOpened() || !images.empty();} ?
? ? //是否停止處理 ?
? ? bool isStopped(){ return stop; } ?
? ? //停止處理 ?
? ? void stopIt(){ stop = true; } ?
? ? //從視頻或攝像頭或圖片文件讀取下一幀 ?
? ? bool readNextFrame(Mat& frame); ?
? ? //設置播放延時 ?
? ? void setDelay(int d){ delay = d;} ?
? ? //設置調用回調函數 ?
? ? void callProcess(){ callIt = true; } ?
? ? //設置不調用回調函數 ?
? ? void dontCallProcess(){ callIt = false;} ?
? ? //設置停留在某幀 ?
? ? void stopAtFrameNo(long frame){ frameToStop = frame;} ?
? ? //返回視頻總幀數 ?
? ? long getFrameNumber(void); ?
? ? //返回輸入視頻的幀頻 ?
? ? long ?getFrameRate(){ return capture.get(CV_CAP_PROP_FPS); } ?
??
private://用于輸出視頻或圖片文件 ?
? ? //opencv用于視頻輸出類對象 ?
? ? VideoWriter writer; ?
? ? //輸出文件名 ?
? ? string outputFile; ?
? ? //輸出圖片的當前索引值 ?
? ? int currentIndex; ?
? ? //輸出圖像的數字編號的位數 ?
? ? int digits; ?
? ? //擴展名 ?
? ? string extension; ?
? ? //保存圖片文件名 ?
? ? vector<string> images; ?
? ? //遍歷圖片vector的迭代器 ?
? ? vector<string>::const_iterator itImg; ?
??
public: ?
? ? //輸出視頻文件以原視頻相同的參數 ?
? ? //還不能正確得到輸入視頻的codec格式,只能在codec==-1時,輸出視頻 ?
? ? bool setOutput(const string& filename, int codec=-1, double framerate=0.0, bool?
isColor=true); ?
? ? //用于輸出每一幀 ?
? ? void writeNextFrame(Mat& frame); ?
? ? //用于以圖片格式輸出 ?
? ? bool setOutput(const string &filename,const string &ext,int numberOfDigits=3, int?
startIndex=0); ?
? ? //獲得輸入視頻的編碼格式 ?
? ? int getCodec(char codec[4]); ?
? ? //獲得圖片大小 ?
? ? cv::Size getFrameSize() ?
? ? { ??
? ? ? ? cv::Size S ; ?
? ? ? ? return S = Size((int) capture.get(CV_CAP_PROP_FRAME_WIDTH), ? ?//獲取輸入尺寸 ?
? ? ? ? ? ? ? (int) capture.get(CV_CAP_PROP_FRAME_HEIGHT)); ??
? ? } ?
public: ?
? ? VideoProcessor(void); ?
? ? ~VideoProcessor(void); ?
? ? ??
? ? //設置輸入圖片向量 ?
? ? bool setInput(const vector<string>& imgs); ?
}; ?
??
</span> ?
?
相應cpp文件:
<span style="font-size:24px;">#include "StdAfx.h" ?
#include "VideoProcessor.h" ?
??
??
VideoProcessor::VideoProcessor(void): ?
? ? callIt(true), ?
? ? delay(0), ?
? ? fnumber(0), ?
? ? stop(false), ?
? ? frameToStop(-1), ?
? ? currentIndex(0), ?
? ? digits(0) ?
{ ?
} ?
????
VideoProcessor::~VideoProcessor(void) ?
{ ?
} ?
????
bool VideoProcessor::setInput(string filename) ?
{ ?
? ? fnumber = 0; ?
? ? //萬一該VideoCapture對象已經關聯了一個資源 ?
? ? capture.release(); ?
? ? //images.clear(); ?
? ? //打開視頻文件 ?
? ? return capture.open(filename); ?
? ? ??
} ?
??
??void VideoProcessor::displayInput(string wn) ?
{ ?
? ? windowNameInput = wn; ?
? ? namedWindow(windowNameInput); ?
} ?
??
??void VideoProcessor::displayOutput(string wn) ?
{ ?
? ? windowNameOutput = wn; ?
? ? namedWindow(windowNameOutput); ?
} ?
????
void VideoProcessor::dontDisplay(void) ?
{ ?
? ? destroyWindow(windowNameInput); ?
? ? destroyWindow(windowNameOutput); ?
? ? windowNameInput.clear(); ?
? ? windowNameOutput.clear(); ?
} ?
???
void VideoProcessor::run(void) ?
{ ?
? ? //當前幀 ?
? ? Mat frame; ?
? ? //輸出幀 ?
? ? Mat output; ?
? ? //判斷是否打開成功 ?
? ? if(!isOpened()) ?
? ? ? ? return; ?
? ? stop = false; ?
? ? while(!isStopped()) ?
? ? { ?
? ? ? ? //若存在視頻下一幀,則讀取 ?
? ? ? ? if(!readNextFrame(frame)) ?
? ? ? ? ? ? break; ?
? ? ? ? //將當前幀存于image中 ?
? ? ? ? image = frame; ?
? ? ? ? //frame.copyTo(image); ?
? ? ? ? //顯示輸入幀 ?
? ? ? ? if(windowNameInput.length() != 0) ?
? ? ? ? ? ? imshow(windowNameInput,frame); ?
? ? ? ? //調用處理函數 ?
? ? ? ? if(callIt) ?
? ? ? ? { ?
? ? ? ? ? ? process(frame,output); ?
? ? ? ? ? ? fnumber++; ?
? ? ? ? }else{ ?
? ? ? ? ? ? output = frame; ?
? ? ? ? } ?
? ? ? ? //**寫輸出序列 ?
? ? ? ? if(outputFile.length() != 0) ?
? ? ? ? ? ? writeNextFrame(output); ?
? ? ? ? //顯示輸出幀 ?
? ? ? ? if(windowNameOutput.length() != 0) ?
? ? ? ? ? ? imshow(windowNameOutput,output); ?
? ? ? ? //延時 ?
? ? ? ? if(delay >= 0 && waitKey(delay) >= 0) ?
? ? ? ? ? ? stopIt(); ?
? ? ? ? if(frameToStop >= 0 && getFrameNumber() == frameToStop) ?
? ? ? ? ? ? stopIt(); ?
? ? } ?
} ?
????
bool VideoProcessor::readNextFrame(Mat& frame) ?
{ ?
? ? if(images.size() == 0) ?
? ? ? ? return capture.read(frame); ?
? ? else{ ?
? ? ? ? if(itImg != images.end()) ?
? ? ? ? { ?
? ? ? ? ? ? frame = imread(*itImg); ?
? ? ? ? ? ? itImg++; ?
? ? ? ? ? ? return frame.data != 0; ?
? ? ? ? }else{ ?
? ? ? ? ? ? return false; ?
? ? ? ? } ?
? ? } ?
} ?
????
long VideoProcessor::getFrameNumber(void) ?
{ ?
? ? long fnumber = static_cast<long>(capture.get(CV_CAP_PROP_POS_FRAMES)); ?
? ? return fnumber; ?
} ?
????
bool VideoProcessor::setOutput(const string& filename, int codec, double framerate, bool?
isColor) ?
{ ?
? ? outputFile = filename; ?
? ? extension.clear(); ?
? ? if(framerate == 0.0) ?
? ? ? ? framerate = getFrameRate(); ?
? ? char c[4]; ?
? ? //使用與輸出視頻相同的編碼方式 ?
? ? if(codec == 0) ?
? ? { ?
? ? ? ? codec = getCodec(c); ?
? ? } ?
? ? ??
? ? writer.open(outputFile, ?
? ? ? ? codec=-1, ?
? ? ? ? framerate, ?
? ? ? ? getFrameSize(), ?
? ? ? ? isColor); ?
? ? if(writer.isOpened()) std::cout<<"dai kai cheng gong"<<std::endl; ?
? ? return true; ?
} ?
????
void VideoProcessor::writeNextFrame(Mat& frame) ?
{ ?
? ? if(extension.length()) ?
? ? { ?
? ? ? ? std::stringstream ss; ?
? ? ? ? //構成輸出文件名 ?
? ? ? ? ss<<outputFile<<std::setfill('0') ?
? ? ? ? ? ? <<std::setw(digits) ?
? ? ? ? ? ? <<currentIndex++<<extension; ?
? ? ? ? imwrite(ss.str(),frame); ?
? ? }else//否則以視頻格式寫出 ?
? ? { ?
? ? ? ? writer.write(frame); ?
? ? } ?
} ?
????
bool VideoProcessor::setOutput(const string &filename,//文件前綴 ?
? ? const string& ext,//圖片文件的擴展名 ?
? ? int numberOfDigits,//數據位 ?
? ? int startIndex) //開始索引值 ?
{ ?
? ? //數字必須為正 ?
? ? if(numberOfDigits<0) ?
? ? return false; ?
? ? //文件名及其擴展名 ?
? ? outputFile = filename; ?
? ? extension = ext; ?
? ? //輸出圖片的編號 ?
? ? digits = numberOfDigits; ?
? ? //圖片數字編號的起始值 ?
? ? currentIndex = startIndex; ?
? ? return true; ?
} ?
????
int VideoProcessor::getCodec(char codec[4]) ?
{ ?
? ? // ?
? ? if(images.size() != 0) ?
? ? ? ? return -1; ?
? ? union{//4-char編碼的數據結構 ?
? ? ? ? int value; ?
? ? ? ? char code[4]; ?
? ? }returned; ?
? ? //獲得編碼方式 ?
? ? returned.value = static_cast<int>( ?
? ? ? ? capture.get(CV_CAP_PROP_FOURCC)); ?
? ? //獲得四個字符 ?
? ? codec[0] = returned.code[0]; ?
? ? codec[1] = returned.code[1]; ?
? ? codec[2] = returned.code[2]; ?
? ? codec[3] = returned.code[3]; ?
? ? /*std::cout << "Codec: " << codec[0] << codec[1] ??
? ? ? ? ? ? ?<< codec[2] << codec[3] << std::endl;*/ ?
? ? return returned.value; ?
} ?
????
bool VideoProcessor::setInput(const vector<string>& imgs) ?
{ ?
? ? fnumber = 0; ?
? ? capture.release(); ?
? ? //將輸入圖片放入iamges中 ?
? ? images = imgs; ?
? ? itImg = images.begin(); ?
? ? return true; ?
} ?
</span> ?
?
主函數對這個類的引用:
<span style="font-size:24px;">#include "stdafx.h" ?
??
#include "VideoProcessor.h" ?
??
using namespace std; ?
using namespace cv; ?
??
void canny(cv::Mat& img, cv::Mat& out) { ?
? ?// Convert to gray ?
? ?if (img.channels()==3) ?
? ? ? cv::cvtColor(img,out,CV_BGR2GRAY); ?
? ?// Compute Canny edges ?
? ?cv::Canny(out,out,100,200); ?
? ?// Invert the image ?
? ?cv::threshold(out,out,128,255,cv::THRESH_BINARY_INV); ?
} ?
int main() ?
{ ? ??
? ? VideoProcessor processor; ?
? ? processor.setInput("../1.avi"); ?
? ? processor.displayInput("Current Frame"); ?
? ? processor.displayOutput("Output Frame"); ?
? ? processor.setDelay(1000./processor.getFrameRate()); ?
? ? processor.setFrameProcessor(canny); ?
? ? processor.setOutput("../laneout.avi"); ?
? ? //processor.setOutput("../laneout",".bmp"); ?
? ? processor.stopAtFrameNo(300); ?
? ? processor.run(); ?
}</span> ?
代碼注釋:輸出視頻和輸出圖片一次只能設置一個。具體應用時,對處理函數的形式進行修改,使其適合
相應程序的要求。
========
使用OpenCV 讀取和處理任意格式視頻文件
?記得幾個月前,使用OpenCV 做背景分割時使用它 很多視頻都不能處理。所以投靠了 directshow,這個
超級復雜的東西。雖然說已經用 directshow 寫了一個幾萬行的商業軟件,說實話對它還是想敬而遠之。
今天在測一段網上的代碼時,竟然都通了。我想這也可能和我在編譯器里鏈接了directshow 的東西吧!
下面貼一段代碼
int main( int argc, char** argv )
{
?//聲明IplImage指針
?IplImage* pFrame = NULL;
?IplImage* pFrImg = NULL;
?IplImage* pBkImg = NULL;
?CvMat* pFrameMat = NULL;
?CvMat* pFrMat = NULL;
?CvMat* pBkMat = NULL;
?CvCapture* pCapture = NULL;
?int nFrmNum = 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])))
?if( !(pCapture = cvCaptureFromFile(videoname2)))
?{
? fprintf(stderr, "Can not open video file %s\n", argv[1]);
? return -2;
?}
?//逐幀讀取視頻
?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);
? ?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);
? ?cvConvert(pFrImg, pFrameMat);
? ?cvConvert(pFrImg, pFrMat);
? ?cvConvert(pFrImg, pBkMat);
? }
? else
? {
? ?cvCvtColor(pFrame, pFrImg, CV_BGR2GRAY);
? ?cvConvert(pFrImg, pFrameMat);
? ?//高斯濾波先,以平滑圖像
? ?//cvSmooth(pFrameMat, pFrameMat, CV_GAUSSIAN, 3, 0, 0);
? ?//當前幀跟背景圖相減
? ?cvAbsDiff(pFrameMat, pBkMat, pFrMat);
? ?//二值化前景圖
? ?cvThreshold(pFrMat, pFrImg, 60, 255.0, CV_THRESH_BINARY);
? ?//進行形態學濾波,去掉噪音?
? ?//cvErode(pFrImg, pFrImg, 0, 1);
? ?//cvDilate(pFrImg, pFrImg, 0, 1);
? ?//更新背景
? ?cvRunningAvg(pFrameMat, pBkMat, 0.003, 0);
? ?//將背景轉化為圖像格式,用以顯示
? ?cvConvert(pBkMat, pBkImg);
? ?//顯示圖像
? ?cvShowImage("video", pFrame);
? ?cvShowImage("background", pBkImg);
? ?cvShowImage("foreground", pFrImg);
? ?//如果有按鍵事件,則跳出循環
? ?//此等待也為cvShowImage函數提供時間完成顯示
? ?//等待時間可以根據CPU速度調整
? ?if( cvWaitKey(2) >= 0 )
? ? break;
? }
?}
?//銷毀窗口
?cvDestroyWindow("video");
?cvDestroyWindow("background");
?cvDestroyWindow("foreground");
?//釋放圖像和矩陣
?cvReleaseImage(&pFrImg);
?cvReleaseImage(&pBkImg);
?cvReleaseMat(&pFrameMat);
?cvReleaseMat(&pFrMat);
?cvReleaseMat(&pBkMat);
?cvReleaseCapture(&pCapture);
?return 0;
}
========
?OpenCV讀視頻文件和運動物體檢測
簡要說明:本程序 嘗試打開本電腦上的攝像頭作為視頻輸入設備,或者將命令行的輸入參數作為文件名
來打開的視頻文件。不管是哪一種方法,最后都是不斷的循環處理一幀一幀地處理,涉及到的圖像處理有?
背景擦除,平滑濾波,二值化等。
有微小調整。在VS2005+OpenCV下調試通過。
?
#include <stdafx.h>?
#include <stdio.h>?
#include <cv.h>?
#include <cxcore.h>?
#include <highgui.h>?
??
int main( int argc, char** argv )?
{?
? ? //聲明IplImage指針?
? ? IplImage* pFrame = NULL; ?
? ? IplImage* pFrImg = NULL;?
? ? IplImage* pBkImg = NULL;?
?
? ? CvMat* pFrameMat = NULL;?
? ? CvMat* pFrMat = NULL;?
? ? CvMat* pBkMat = NULL;?
?
? ? CvCapture* pCapture = NULL;?
?
? ? int nFrmNum = 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(0)))?
? ? ? ? {?
? ? ? ? ? ? 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;?
? ? ? ? }?
? ? }?
? ? //逐幀讀取視頻?
? ? 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);?
?
? ? ? ? ? ? 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);?
?
? ? ? ? ? ? cvConvert(pFrImg, pFrameMat);?
? ? ? ? ? ? cvConvert(pFrImg, pFrMat);?
? ? ? ? ? ? cvConvert(pFrImg, pBkMat);?
? ? ? ? }?
? ? ? ? else?
? ? ? ? {?
? ? ? ? ? ? cvCvtColor(pFrame, pFrImg, CV_BGR2GRAY);?
? ? ? ? ? ? cvConvert(pFrImg, pFrameMat);?
? ? ? ? ? ? //高斯濾波先,以平滑圖像?
? ? ? ? ? ? //cvSmooth(pFrameMat, pFrameMat, CV_GAUSSIAN, 3, 0, 0);?
?
? ? ? ? ? ? //當前幀跟背景圖相減?
? ? ? ? ? ? cvAbsDiff(pFrameMat, pBkMat, pFrMat);?
?
? ? ? ? ? ? //二值化前景圖?
? ? ? ? ? ? cvThreshold(pFrMat, pFrImg, 60, 255.0, CV_THRESH_BINARY);?
?
? ? ? ? ? ? //進行形態學濾波,去掉噪音 ??
? ? ? ? ? ? //cvErode(pFrImg, pFrImg, 0, 1);?
? ? ? ? ? ? //cvDilate(pFrImg, pFrImg, 0, 1);?
?
? ? ? ? ? ? //更新背景?
? ? ? ? ? ? cvRunningAvg(pFrameMat, pBkMat, 0.003, 0);?
? ? ? ? ? ? //將背景轉化為圖像格式,用以顯示?
? ? ? ? ? ? cvConvert(pBkMat, pBkImg);?
?
? ? ? ? ? ? //顯示圖像?
? ? ? ? ? ? cvShowImage("video", pFrame);?
? ? ? ? ? ? cvShowImage("background", pBkImg);?
? ? ? ? ? ? cvShowImage("foreground", pFrImg);?
?
? ? ? ? ? ? //如果有按鍵事件,則跳出循環?
? ? ? ? ? ? //此等待也為cvShowImage函數提供時間完成顯示?
? ? ? ? ? ? //等待時間可以根據CPU速度調整?
? ? ? ? ? ? if( cvWaitKey(2) >= 0 )?
? ? ? ? ? ? ? ? break;?
? ? ? ? }?
? ? }?
? ? ?
? ? //銷毀窗口?
? ? cvDestroyWindow("video");?
? ? cvDestroyWindow("background");?
? ? cvDestroyWindow("foreground");?
?
? ? //釋放圖像和矩陣?
? ? cvReleaseImage(&pFrImg);?
? ? cvReleaseImage(&pBkImg);?
?
? ? cvReleaseMat(&pFrameMat);?
? ? cvReleaseMat(&pFrMat);?
? ? cvReleaseMat(&pBkMat);?
?
? ? cvReleaseCapture(&pCapture);?
?
? ? return 0;?
}?
========
基于輪廓尋找的視頻流運動檢測
#include "cv.h"#include "highgui.h"
#include <time.h>
#include <math.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
// various tracking parameters (in seconds) //跟蹤的參數(單位為秒)
const double MHI_DURATION = 0.5;//0.5s為運動跟蹤的最大持續時間
const double MAX_TIME_DELTA = 0.5;
const double MIN_TIME_DELTA = 0.05;
const int N = 3;
//
const int CONTOUR_MAX_AERA = 1000;
// ring image buffer 圈出圖像緩沖
IplImage **buf = 0;//指針的指針
int last = 0;
// temporary images臨時圖像
IplImage *mhi = 0; // MHI: motion history image
CvFilter filter = CV_GAUSSIAN_5x5;
CvConnectedComp *cur_comp, min_comp;
CvConnectedComp comp;
CvMemStorage *storage;
CvPoint pt[4];
// ?參數:
// ?img – 輸入視頻幀
// ?dst – 檢測結果
void ?update_mhi( IplImage* img, IplImage* dst, int diff_threshold )
{
? ? double timestamp = clock()/100.; // get current time in seconds 時間戳
? ? CvSize size = cvSize(img->width,img->height);
? ? // get current frame size,得到當前幀的尺寸
? ? int i, idx1, idx2;
? ? IplImage* silh;
? ? IplImage* pyr = cvCreateImage( cvSize((size.width & -2)/2, (size.height & -2)/2), 8, 1?
);
? ? CvMemStorage *stor;
? ? CvSeq *cont;
? ? /*先進行數據的初始化*/
? ? if( !mhi || mhi->width != size.width || mhi->height != size.height )
? ? {
? ? ? ? if( buf == 0 ) //若尚沒有初始化則分配內存給他
? ? ? ? {
? ? ? ? ? ? buf = (IplImage**)malloc(N*sizeof(buf[0]));
? ? ? ? ? ? memset( buf, 0, N*sizeof(buf[0]));
? ? ? ? }
? ? ? ??
? ? ? ? for( i = 0; i < N; i++ )
? ? ? ? {
? ? ? ? ? ? cvReleaseImage( &buf[i] );
? ? ? ? ? ? buf[i] = cvCreateImage( size, IPL_DEPTH_8U, 1 );
? ? ? ? ? ? cvZero( buf[i] );// clear Buffer Frame at the beginning
? ? ? ? }
? ? ? ? cvReleaseImage( &mhi );
? ? ? ? mhi = cvCreateImage( size, IPL_DEPTH_32F, 1 );
? ? ? ? cvZero( mhi ); // clear MHI at the beginning
? ? } // end of if(mhi)
? ? /*將當前要處理的幀轉化為灰度放到buffer的最后一幀中*/
? ? cvCvtColor( img, buf[last], CV_BGR2GRAY ); // convert frame to grayscale
? ? /*設定幀的序號*/
? ? /*
? ? last---->idx1
? ? ?^
? ? ?|
? ? ?|
? ? ?|
? ? idx2<-----(last+1)%3
? ? */
? ??
? ? idx1 = last;
? ? idx2 = (last + 1) % N; // index of (last - (N-1))th frame
? ? last = idx2;
? ? // 做幀差
? ? silh = buf[idx2];//差值的指向idx2 |idx2-idx1|-->idx2(<-silh)
? ? cvAbsDiff( buf[idx1], buf[idx2], silh ); // get difference between frames
? ??
? ? // 對差圖像做二值化
? ? cvThreshold( silh, silh, 30, 255, CV_THRESH_BINARY ); //threshold it,二值化
? ??
? ? cvUpdateMotionHistory( silh, mhi, timestamp, MHI_DURATION ); // update MHI
?
? ? cvConvert( mhi, dst );//將mhi轉化為dst,dst=mhi ??
? ??
? ? // 中值濾波,消除小的噪聲
? ? cvSmooth( dst, dst, CV_MEDIAN, 3, 0, 0, 0 );
? ??
? ??
? ? cvPyrDown( dst, pyr, CV_GAUSSIAN_5x5 );// 向下采樣,去掉噪聲,圖像是原圖像的四分之一
? ? cvDilate( pyr, pyr, 0, 1 ); ?// 做膨脹操作,消除目標的不連續空洞
? ? cvPyrUp( pyr, dst, CV_GAUSSIAN_5x5 );// 向上采樣,恢復圖像,圖像是原圖像的四倍
? ? //
? ? // 下面的程序段用來找到輪廓
? ? //
? ? // Create dynamic structure and sequence.
? ? stor = cvCreateMemStorage(0);
? ? cont = cvCreateSeq(CV_SEQ_ELTYPE_POINT, sizeof(CvSeq), sizeof(CvPoint) , stor);
? ??
? ? // 找到所有輪廓
? ? cvFindContours( dst, stor, &cont, sizeof(CvContour),
? ? ? ? ? ? ? ? ? ? CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0));
? ? // 直接使用CONTOUR中的矩形來畫輪廓
? ? for(;cont;cont = cont->h_next)
? ? {
? ? ? ? ? ? ? CvRect r = ((CvContour*)cont)->rect;
? ? ? ? ? ? ? if(r.height * r.width > CONTOUR_MAX_AERA) // 面積小的方形拋棄掉
? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? cvRectangle( img, cvPoint(r.x,r.y),
? ? ? ? ? ? ? ? ? ? ? ? ? cvPoint(r.x + r.width, r.y + r.height),
? ? ? ? ? ? ? ? ? ? ? ? ? CV_RGB(255,0,0), 1, CV_AA,0);
? ? ? ? ? ? ? }
? ? }
? ? // free memory
? ? cvReleaseMemStorage(&stor);
? ? cvReleaseImage( &pyr );
}
int main(int argc, char** argv)
{
? ? IplImage* motion = 0;
? ? CvCapture* capture = 0;
? ??
? ? if( argc == 1 || (argc == 2 && strlen(argv[1]) == 1 && isdigit(argv[1][0])))
? ? ? ? capture = cvCaptureFromCAM( argc == 2 ? argv[1][0] - '0' : 0 );//攝像頭為視頻來源
? ? else if( argc == 2 )
? ? ? ? capture = cvCaptureFromAVI( argv[1] );//AVI為視頻來源
? ? if( capture )
? ? {
? ? ? ? cvNamedWindow( "Motion", 1 );//建立窗口
? ? ? ? for(;;)
? ? ? ? {
? ? ? ? ? ? IplImage* image;
? ? ? ? ? ? if( !cvGrabFrame( capture ))//捕捉一楨
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? image = cvRetrieveFrame( capture );//取出這個幀
? ? ? ? ? ? if( image )//若取到則判斷motion是否為空
? ? ? ? ? ? {
? ? ? ? ? ? ? ? if( !motion )
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? motion = cvCreateImage( cvSize(image->width,image->height), 8, 1 );
? ? ? ? ? ? ? ? ? ? //創建motion幀,八位,一通道
? ? ? ? ? ? ? ? ? ? cvZero( motion );
? ? ? ? ? ? ? ? ? ? //零填充motion
? ? ? ? ? ? ? ? ? ? motion->origin = image->origin;
? ? ? ? ? ? ? ? ? ? //內存存儲的順序和取出的幀相同
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ? update_mhi( image, motion, 60 );//更新歷史圖像
? ? ? ? ? ? cvShowImage( "Motion", image );//顯示處理過的圖像
? ? ? ? ? ? if( cvWaitKey(10) >= 0 )//10ms中按任意鍵退出
? ? ? ? ? ? ? ? break;
? ? ? ? }
? ? ? ? cvReleaseCapture( &capture );//釋放設備
? ? ? ? cvDestroyWindow( "Motion" );//銷毀窗口
? ? }
? ? return 0;
}?
========
?OpenCV讀視頻文件和運動問題檢測
下面這個程序 來自于仕琪的講稿 《使用OpenCV進行圖像處理》]中的例程:cvRunningAvg
opencv中的函數,用來更新移動平均。用法:
void cvRunningAvg(const CvArr * image,
CvArr* acc,
double alpha,
const CvArr* mask=NULL)
image:輸入圖像,1或3通道,8比特或32比特的float型
acc:累加器,和image一樣大小
alpha:更新時,image所占的權重
mask:操作符掩碼
if mask(x,y)!= 0 (1-alpha)*acc(x,y)+alpha*image(x,y) =>acc(x,y)
#if 0 ?
#include <stdio.h> ?
?#include <cv.h> ?
#include <cxcore.h> ?
#include <highgui.h> ?
??
#pragma comment(lib, "cv.lib") ?
#pragma comment(lib, "cxcore.lib") ?
#pragma comment(lib, "highgui.lib") ?
??
int main( int argc, char** argv ) ?
{ ?
? ? //聲明IplImage指針 ?
? ? IplImage* pFrame = NULL; ??
? ? IplImage* pFrImg = NULL; ?
? ? IplImage* pBkImg = NULL; ?
??
? ? CvMat* pFrameMat = NULL; ?
? ? CvMat* pFrMat = NULL; ?
? ? CvMat* pBkMat = NULL; ?
??
? ? CvCapture* pCapture = NULL; ?
??
? ? int nFrmNum = 0; ?
??
? ? //創建窗口 ?
? ? cvNamedWindow("video", 1); ?
? ? cvNamedWindow("background",1); ?
? ? cvNamedWindow("foreground",1); ?
? ? //使窗口有序排列 ?
? ? cvMoveWindow("video", 30, 0); ?
? ? cvMoveWindow("background", 360, 0); ?
? ? cvMoveWindow("foreground", 690, 0); ?
??
??
? ? if( !(pCapture = cvCaptureFromAVI(".\\test.avi"))) ?
? ? { ?
? ? ? ? //pCapture = cvCaptureFromCAM(-1)) ?
? ? ? ? fprintf(stderr, "Can not open camera.\n"); ?
? ? ? ? return -2; ?
? ? } ?
??
? ? //逐幀讀取視頻 ?
? ? 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); ?
??
? ? ? ? ? ? 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); ?
??
? ? ? ? ? ? cvConvert(pFrImg, pFrameMat); ?
? ? ? ? ? ? cvConvert(pFrImg, pFrMat); ?
? ? ? ? ? ? cvConvert(pFrImg, pBkMat); ?
? ? ? ? } ?
? ? ? ? else ?
? ? ? ? { ?
? ? ? ? ? ? cvCvtColor(pFrame, pFrImg, CV_BGR2GRAY); ?
? ? ? ? ? ? cvConvert(pFrImg, pFrameMat); ?
? ? ? ? ? ? //高斯濾波先,以平滑圖像 ?
? ? ? ? ? ? //cvSmooth(pFrameMat, pFrameMat, CV_GAUSSIAN, 3, 0, 0); ?
??
? ? ? ? ? ? //當前幀跟背景圖相減 ?
? ? ? ? ? ? cvAbsDiff(pFrameMat, pBkMat, pFrMat); ?
??
? ? ? ? ? ? //二值化前景圖 ?
? ? ? ? ? ? cvThreshold(pFrMat, pFrImg, 60, 255.0, CV_THRESH_BINARY); ?
??
? ? ? ? ? ? //進行形態學濾波,去掉噪音 ? ?
? ? ? ? ? ? //cvErode(pFrImg, pFrImg, 0, 1); ?
? ? ? ? ? ? //cvDilate(pFrImg, pFrImg, 0, 1); ?
??
? ? ? ? ? ? //更新背景 ?
? ? ? ? ? ? cvRunningAvg(pFrameMat, pBkMat, 0.003, 0); ?
? ? ? ? ? ? //將背景轉化為圖像格式,用以顯示 ?
? ? ? ? ? ? cvConvert(pBkMat, pBkImg); ?
??
? ? ? ? ? ? //顯示圖像 ?
? ? ? ? ? ? cvShowImage("video", pFrame); ?
? ? ? ? ? ? cvShowImage("background", pBkImg); ?
? ? ? ? ? ? cvShowImage("foreground", pFrImg); ?
??
? ? ? ? ? ? //如果有按鍵事件,則跳出循環 ?
? ? ? ? ? ? //此等待也為cvShowImage函數提供時間完成顯示 ?
? ? ? ? ? ? //等待時間可以根據CPU速度調整 ?
? ? ? ? ? ? if( cvWaitKey(20) >= 0 ) ?
? ? ? ? ? ? { ?
? ? ? ? ? ? ? ? break; ?
? ? ? ? ? ? } ?
? ? ? ? } ?
? ? } ?
? ? cvWaitKey(); ?
??
? ? //銷毀窗口 ?
? ? cvDestroyWindow("video"); ?
? ? cvDestroyWindow("background"); ?
? ? cvDestroyWindow("foreground"); ?
??
? ? //釋放圖像和矩陣 ?
? ? cvReleaseImage(&pFrImg); ?
? ? cvReleaseImage(&pBkImg); ?
??
? ? cvReleaseMat(&pFrameMat); ?
? ? cvReleaseMat(&pFrMat); ?
? ? cvReleaseMat(&pBkMat); ?
??
? ? cvReleaseCapture(&pCapture); ?
??
? ? return 0; ?
} ?
#else ?
#include <cv.h> ?
#include <highgui.h> ?
??
#pragma comment(lib, "cv.lib") ?
#pragma comment(lib, "cxcore.lib") ?
#pragma comment(lib, "highgui.lib") ?
??
int main( int argc, char** argv ) ?
{ ?
? ? CvCapture* capture = NULL; ?
? ? IplImage *frame = NULL; ?
??
? ? IplImage ?*frame_last = NULL;//存儲上一幀 ?
? ? IplImage ?*m_out_image = NULL; ?
??
? ? IplImage* frame_gray = NULL; ?
? ? IplImage* frame_gray_last = NULL; ?
? ? IplImage* m_out_image_copy = NULL; ?
? ? int nFrmNum = 0; ?
??
? ? //capture = cvCaptureFromCAM(-1); ??
??
? ? capture = cvCaptureFromAVI(".\\test.avi"); ?
??
? ? //創建窗口 ?
? ? cvNamedWindow( "result", 1 ); ?
? ? cvNamedWindow("差分"); ?
??
? ? //逐幀讀取視頻 ?
? ? while(frame = cvQueryFrame( capture )) ?
? ? { ?
? ? ? ? nFrmNum++; ?
??
? ? ? ? //如果是第一幀,需要申請內存,并初始化 ?
? ? ? ? if(nFrmNum == 1) ?
? ? ? ? { ?
? ? ? ? ? ? frame_last = cvCreateImage(cvSize(frame->width,frame->height),IPL_DEPTH_8U,?
frame->nChannels); ?
? ? ? ? ? ? cvCopy(frame,frame_last); ?
? ? ? ? } ?
? ? ? ? else ?
? ? ? ? { ?
? ? ? ? ? ? frame_gray = cvCreateImage(cvSize(frame->width,frame->height),IPL_DEPTH_8U, 1); ?
? ? ? ? ? ? frame_gray_last = cvCreateImage(cvSize(frame->width,frame->height),IPL_DEPTH_8U,?
1); ?
??
? ? ? ? ? ? m_out_image = cvCreateImage(cvSize(frame->width,frame->height),IPL_DEPTH_8U, 1);?
? ? ? ? ? ? m_out_image_copy = cvCreateImage( cvSize(frame->width,frame-
>height),IPL_DEPTH_8U, 1 ); ?
??
? ? ? ? ? ? cvCvtColor(frame,frame_gray,CV_RGB2GRAY); ???
? ? ? ? ? ? cvCvtColor(frame_last,frame_gray_last,CV_RGB2GRAY); ???
? ? ? ? ? ? cvAbsDiff(frame_gray,frame_gray_last,m_out_image); ???
? ? ? ? ? ? //cvThreshold(m_out_image,m_out_image,128, 255,CV_THRESH_BINARY); ?
??
? ? ? ? ? ? //將處理后的圖像寫出到第二個圖像中 ?
??
? ? ? ? ? ? if( m_out_image_copy->origin == IPL_ORIGIN_TL ) ?
? ? ? ? ? ? { ?
? ? ? ? ? ? ? ? cvCopy( m_out_image, m_out_image_copy, 0 ); ?
? ? ? ? ? ? } ?
? ? ? ? ? ? else ?
? ? ? ? ? ? { ?
? ? ? ? ? ? ? ? cvFlip( m_out_image, m_out_image_copy, 0 ); ?
? ? ? ? ? ? } ?
??
? ? ? ? ? ? frame_last = cvCreateImage(cvSize(frame->width,frame->height),IPL_DEPTH_8U,?
frame->nChannels); ?
? ? ? ? ? ? cvCopy(frame,frame_last); ?
??
? ? ? ? ? ? cvShowImage("差分",m_out_image_copy); ?
? ? ? ? ? ? cvShowImage("result",frame); ?
??
? ? ? ? ? ? cvReleaseImage( &m_out_image_copy ); ?
? ? ? ? ? ? cvReleaseImage( &frame_gray_last ); ?
? ? ? ? ? ? cvReleaseImage( &frame_gray ); ?
??
? ? ? ? ? ? if( cvWaitKey( 20 ) >= 0 ) ?
? ? ? ? ? ? { ?
? ? ? ? ? ? ? ? break; ?
? ? ? ? ? ? } ?
? ? ? ? } ?
? ? } ?
? ? cvWaitKey(); ?
??
? ? cvReleaseImage( &m_out_image ); ?
? ? cvReleaseImage( &frame_last ); ?
? ? cvReleaseImage( &frame ); ?
??
? ? cvReleaseCapture( &capture ); ?
??
? ? cvDestroyWindow("result"); ?
? ? cvDestroyWindow("差分"); ?
??
? ? return 0; ?
} ?
#endif
========
Opencv中對視頻流進行邊緣檢測
#include "stdafx.h" ?#include "cv.h" ?
#include "highgui.h" ?
#include <ctype.h> ?
#include <stdio.h> ?
int main( int argc, char** argv ) ?
{ ?
? ? IplImage* laplace = 0; ?
? ? IplImage* colorlaplace = 0; ?
? ? IplImage* planes[3] = { 0, 0, 0 }; ?// 多個圖像面 ?
? ? CvCapture* capture = 0; ?
? ? //CvCapture ?
? ? // ?
? ? //視頻獲取結構 ?
? ? //typedef struct CvCapture CvCapture; ?
? ? //結構CvCapture 沒有公共接口,它只能被用來作為視頻獲取函數的一個參數。 ?
? ? // 下面的語句說明在命令行執行程序時,如果指定AVI文件,那么處理從 ?
? ? // AVI文件讀取的視頻流,如果不指定輸入變量,那么處理從攝像頭獲取 ?
? ? // 的視頻流 ?
? ? ??
? ? //capture = cvCaptureFromAVI( "3.avi" ); ?
??
? ? if( argc == 1 || (argc == 2 && strlen(argv[1]) == 1 && isdigit(argv[1][0]))) ?
? ? ? ? capture = cvCaptureFromCAM( argc == 2 ? argv[1][0] - '0' : 0 ); ?
? ? else if( argc == 2 ) ?
? ? ? ? capture = cvCaptureFromAVI( argv[1] ); ??
??
? ? if( !capture ) ?
? ? { ?
? ? ? ? fprintf(stderr,"Could not initialize capturing...\n"); ?
? ? ? ? return -1; ?
? ? } ?
? ? cvNamedWindow( "Laplacian", 0 ); ?
? ? // 循環捕捉,直到用戶按鍵跳出循環體 ?
? ? for(;;) ?
? ? { ?
? ? ? ? IplImage* frame = 0; ?
? ? ? ? int i; ?
? ? ? ? //cvQueryFrame ?
? ? ? ? // ?
? ? ? ? //從攝像頭或者文件中抓取并返回一幀 ?
? ? ? ? //IplImage* cvQueryFrame( CvCapture* capture ); ?
? ? ? ? //capture ??
? ? ? ? //視頻獲取結構。 ?
? ? ? ? //函數cvQueryFrame從攝像頭或者文件中抓取一幀,然后解壓并返回這一幀。 ?
? ? ? ? //這個函數僅僅是函數cvGrabFrame和函數cvRetrieveFrame在一起調用的組合。 ?
? ? ? ? //返回的圖像不可以被用戶釋放或者修改。 抓取后,capture被指向下一幀, ?
? ? ? ? //可用cvSetCaptureProperty調整capture到合適的幀。 ?
? ? ? ? // ?
? ? ? ? //注意: cvQueryFrame返回的指針總是指向同一塊內存。建議cvQueryFrame后拷貝一份 ?
? ? ? ? //。而且返回的幀需要FLIP后才符合OPENCV的坐標系。 若返回值為NULL,說明到了視頻的最后
一幀。 ?
? ? ? ? frame = cvQueryFrame( capture ); ?
? ? ? ? if( !frame ) ?
? ? ? ? ? ? break; ?
? ? ? ? if( !laplace ) ?
? ? ? ? { ?
? ? ? ? ? ? for( i = 0; i < 3; i++ ) ?
? ? ? ? ? ? ? ? planes[i] = cvCreateImage( cvSize(frame->width,frame->height), 8, 1 ); ?
? ? ? ? ? ? //CreateImage ?
? ? ? ? ? ? //創建頭并分配數據 ?
? ? ? ? ? ? //IplImage* cvCreateImage( CvSize size, int depth, int channels ); ?
? ? ? ? ? ? //size ?
? ? ? ? ? ? //圖像寬、高. ?
? ? ? ? ? ? //depth ??
? ? ? ? ? ? //圖像元素的位深度,可以是下面的其中之一: ?
? ? ? ? ? ? //IPL_DEPTH_8U - 無符號8位整型 ?
? ? ? ? ? ? //IPL_DEPTH_8S - 有符號8位整型 ?
? ? ? ? ? ? //IPL_DEPTH_16U - 無符號16位整型 ?
? ? ? ? ? ? //IPL_DEPTH_16S - 有符號16位整型 ?
? ? ? ? ? ? //IPL_DEPTH_32S - 有符號32位整型 ?
? ? ? ? ? ? //IPL_DEPTH_32F - 單精度浮點數 ?
? ? ? ? ? ? //IPL_DEPTH_64F - 雙精度浮點數 ?
? ? ? ? ? ? //channels ??
? ? ? ? ? ? //每個元素(像素)的顏色通道數量.可以是 1, 2, 3 或 4.通道是交叉存取的,例如通常
的彩色圖像數據排列是: ?
? ? ? ? ? ? //b0 g0 r0 b1 g1 r1 ... ?
? ? ? ? ? ? //雖然通常 IPL 圖象格式可以存貯非交叉存取的圖像,并且一些OpenCV 也能處理他, 但是
這個函數只能創建交叉存取圖像. ?
? ? ? ? ? ? //函數 cvCreateImage 創建頭并分配數據,這個函數是下列的縮寫型式 ?
? ? ? ? ? ? //header = cvCreateImageHeader(size,depth,channels); ?
? ? ? ? ? ? //cvCreateData(header); //只是創建空間,并不會初始化空間內的數據 ?
? ? ? ? ? ? laplace = cvCreateImage( cvSize(frame->width,frame->height), ?
? ? ? ? ? ? ? ? IPL_DEPTH_16S, 1 ); ?
? ? ? ? ? ? colorlaplace = cvCreateImage( cvSize(frame->width,frame->height), 8, 3 ); ?
? ? ? ? } ?
? ? ? ? //cvCvtPixToPlane ?
? ? ? ? // ?
? ? ? ? // openCV里面的一個函數 ?
? ? ? ? // 可以看作cvSplit是他的宏: ?
? ? ? ? // #define cvCvtPixToPlane cvSplit ?
? ? ? ? // void cvSplit( const CvArr* src, CvArr* dst0, CvArr* dst1,CvArr* dst2, CvArr*?
dst3 ); ?
? ? ? ? // 作用是:分割多通道數組成幾個單通道數組或者從數組中提取一個通道 ?
? ? ? ? // 一般用法是cvCvtPixToPlane(IplImage * src,IplImage * dst1,IplImage?
*dst2,IplImage * dst3,IplImage *dst4) ?
? ? ? ? // 第一個參數是源圖像,后面是分離出來每個通道的目標圖像,如果圓筒到時3通道的,可
以把最后一個參數設置為空。 ?
? ? ? ? // ?例如cvCvtPixToPlane(IplImage * src,IplImage * dst1,IplImage *dst2,IplImage *?
dst3,NULL) ?
? ? ? ? cvCvtPixToPlane( frame, planes[0], planes[1], planes[2], 0 ); ?
? ? ? ? for( i = 0; i < 3; i++ ) ?
? ? ? ? { ?
? ? ? ? ? ? // ? ? ? ? ?Laplace ?
? ? ? ? ? ? //計算圖像的 Laplacian 變換 ?
? ? ? ? ? ? //void cvLaplace( const CvArr* src, CvArr* dst, int aperture_size=3 ); ?
? ? ? ? ? ? //src ?
? ? ? ? ? ? //輸入圖像. ?
? ? ? ? ? ? //dst ?
? ? ? ? ? ? //輸出圖像. ?
? ? ? ? ? ? //aperture_size ?
? ? ? ? ? ? //核大小 (與 cvSobel 中定義一樣). ?
? ? ? ? ? ? cvLaplace( planes[i], laplace, 3 ); // 3: aperture_size ?
? ? ? ? ? ? //ConvertScaleAbs ?
? ? ? ? ? ? //使用線性變換轉換輸入數組元素成8位無符號整型 ?
? ? ? ? ? ? //void cvConvertScaleAbs( const CvArr* src, CvArr* dst, double scale=1, double?
shift=0 ); ?
? ? ? ? ? ? //#define cvCvtScaleAbs cvConvertScaleAbs ?
? ? ? ? ? ? //src ?
? ? ? ? ? ? //原數組 ?
? ? ? ? ? ? //dst ?
? ? ? ? ? ? //輸出數組 (深度為 8u). ?
? ? ? ? ? ? //scale ?
? ? ? ? ? ? //比例因子. ?
? ? ? ? ? ? //shift ?
? ? ? ? ? ? //原數組元素按比例縮放后添加的值。 ?
? ? ? ? ? ? //函數 cvConvertScaleAbs 與前一函數是相同的,但它是存貯變換結果的絕對值: ?
? ? ? ? ? ? //dst(I)=abs(src(I)*scale + (shift,shift,...)) ?
? ? ? ? ? ? //函數只支持目標數數組的深度為 8u (8-bit 無符號) , 對于別的類型函數仿效于
cvConvertScale 和 cvAbs 函數的聯合 ?
? ? ? ? ? ? cvConvertScaleAbs( laplace, planes[i], 1, 0 ); ?// planes[] = ABS(laplace) ?
? ? ? ? } ?
? ? ? ? //cvCvtPixToPlane是cvCvtPlaneToPix的逆函數 ?
? ? ? ? cvCvtPlaneToPix( planes[0], planes[1], planes[2], 0, colorlaplace ); ?
? ? ? ? //IplImage ?
? ? ? ? // ?IPL 圖像頭 ?
? ? ? ? // ?typedef struct _IplImage ?
? ? ? ? //{ ?
? ? ? ? // ?int ?nSize; ? ? ? ? ??
? ? ? ? // ?int ?ID; ? ? ? ? ? ? ?
? ? ? ? // ?int ?nChannels; ? ? ??
? ? ? ? // ?int ?alphaChannel; ? ?
? ? ? ? // ?int ?depth; ? ? ? ? ??
? ? ? ? // ?char colorModel[4]; ??
? ? ? ? // ?char channelSeq[4]; ??
? ? ? ? // ?int ?dataOrder; ? ? ??
? ? ? ? // ?int ?origin; ? ? ? ? ?
? ? ? ? // ?int ?align; ? ? ? ? ??
? ? ? ? // ?int ?width; ? ? ? ? ??
? ? ? ? // ?int ?height; ? ? ? ? ?
? ? ? ? // ?struct _IplROI *roi; ?
? ? ? ? // ?struct _IplImage *maskROI; ??
? ? ? ? // ?void ?*imageId; ? ? ??
? ? ? ? // ?struct _IplTileInfo *tileInfo; ??
? ? ? ? // ?int ?imageSize; ? ? ??
? ? ? ? // ?char *imageData; ? ?
? ? ? ? // ?int ?widthStep; ? ??
? ? ? ? // ?int ?BorderMode[4]; ??
? ? ? ? // ?int ?BorderConst[4]; ??
? ? ? ? // ?char *imageDataOrigin; ??
? ? ? ? //} ?
? ? ? ? // ? ?IplImage; ?
? ? ? ? //IplImage結構來自于 Intel Image Processing Library(是其本身所具有的)。OpenCV 只支
持其中的一個子集: ?
? ? ? ? //alphaChannel 在OpenCV中被忽略。 ?
? ? ? ? //colorModel 和channelSeq 被OpenCV忽略。OpenCV顏色轉換的唯一函數 cvCvtColor把原圖像
的顏色空間的目標圖像的顏色空間作為一個參數。 ?
? ? ? ? //dataOrder 必須是IPL_DATA_ORDER_PIXEL (顏色通道是交叉存取),然而平面圖像的被選擇通
道可以被處理,就像COI(感興趣的通道)被設置過一樣。 ?
? ? ? ? //align 是被OpenCV忽略的,而用 widthStep 去訪問后繼的圖像行。 ?
? ? ? ? //不支持maskROI 。處理MASK的函數把他當作一個分離的參數。MASK在 OpenCV 里是 8-bit,然
而在 IPL他是 1-bit。 ?
? ? ? ? //tileInfo 不支持。 ?
? ? ? ? //BorderMode和BorderConst是不支持的。每個 OpenCV 函數處理像素的鄰近的像素,通常使用
單一的固定代碼邊際模式。 ?
? ? ? ? //除了上述限制,OpenCV處理ROI有不同的要求。要求原圖像和目標圖像的尺寸或 ROI的尺寸必
須(根據不同的操作, ?
? ? ? ? //例如cvPyrDown 目標圖像的寬(高)必須等于原圖像的寬(高)除以2 ±1)精確匹配,而IPL
處理交叉區域,如圖像的大小或ROI大小可能是完全獨立的。 ?
? ? ? ? colorlaplace->origin = frame->origin; ? //讓他們結構一致 ?
? ? ? ? cvShowImage("Laplacian", colorlaplace ); ?
? ? ? ? if( cvWaitKey(10) >= 0 ) ?
? ? ? ? ? ? break; ?
? ? } ?
? ? cvReleaseCapture( &capture ); ?
? ? cvDestroyWindow("Laplacian"); ?
? ? return 0; ?
========
總結
以上是生活随笔為你收集整理的opencv视频处理和检测学习总结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ArcGIS Engine 开发中用到的
- 下一篇: opencv入门 - 显示图像学习总结