前言
在学习OpenCV库的时候,发现了可能由于版本更新,导致的书上的代码无法实现的情况。特此把没一个例子的代码和完整的编译运行命令都记录下来。并记录要点,以备复习。
第二章
一,显示图像
- 程序
-
//用于从磁盘加载图片并在屏幕上显示的简单OpenCv程序 #include"highgui.h" int main(int argc,char ** argv) { //将图像文件加载至内存 IplImage* img = cvLoadImage(argv[1] , 1); //创建窗口,指定标题,设置尺寸为匹配图像大小 cvNamedWindow("Example1",CV_WINDOW_AUTOSIZE); //在已有窗口中显示IplImage指针指向的图像 cvShowImage("Example1",img); //等待用户按键,暂停程序 cvWaitKey(0); //释放内存 cvReleaseImage(&img); //销毁窗口 cvDestroyWindow("Example1"); return 0; }
- 编译过程和运行
xbw@xbw-VirtualBox:~/code/cv_test$ gcc 1_test.c `pkg-config --cflags --libs opencv`
xbw@xbw-VirtualBox:~/code/cv_test$ ./a.out original.jpg
- 要点
函数cvLoadImage()书中仅有一个文件指针参数,实际上有两个。
函数原型:IplImage* cvLoadImage( const char* filename, int flags=CV_LOAD_IMAGE_COLOR );
指定的颜色可以将输入的图片转为3信道(CV_LOAD_IMAGE_COLOR), 单信道(CV_LOAD_IMAGE_GRAYSCALE), 或者保持不变(CV_LOAD_IMAGE_ANYCOLOR)。
cvLoadImage函数使用方法
cvLoadImage( filename, -1 ); 默认读取图像的原通道数
cvLoadImage( filename, 0 ); 强制转化读取图像为灰度图
cvLoadImage( filename, 1 ); 读取彩色图
二,显示视频
- 程序
-
//循环读取视频的每一帧达到播放视频的效果 #include"highgui.h" int main(int argc,char** argv) { //创建窗口 cvNamedWindow("Example2",CV_WINDOW_AUTOSIZE); //读取avi文件,创建CvCapture结构指针 CvCapture* capture = cvCreateFileCapture(argv[1]); IplImage* frame; while(1) { //将下一帧视频文件载入内存 frame = cvQueryFrame(capture); if(!frame) break; cvShowImage("Example2",frame); //如果没有按ESC,延迟200ms char c = cvWaitKey(200); if(c == 27) break; } //释放CvCapture内存 cvReleaseCapture(&capture); cvDestroyWindow("Example2"); return 0; }
- 编译过程和运行
xbw@xbw-VirtualBox:~/code/cv_test$ gcc 1_test.c `pkg-config --cflags --libs opencv`
xbw@xbw-VirtualBox:~/code/cv_test$ ./a.out tree.avi
- 要点
并非实际的播放视频,可以通过延迟时间的方式来控制播放帧率,后面可以通过CvCapture结构体来确定准确帧率。
结构都是:创建窗口,读取文件,播放图片,释放内存,销毁窗口。一次完成,没什么问题。
三,添加视频进度条
- 程序
-
#include"highgui.h" #include"cv.h" //添加滚动条位置的全局变量 int g_slider_position = 0; CvCapture* g_capture = NULL; //回调函数 void onTrackbarSlide(int pos) { cvSetCaptureProperty( g_capture, CV_CAP_PROP_POS_FRAMES, pos ); } int main(int argc,char** argv) { cvNamedWindow("Example3",CV_WINDOW_AUTOSIZE); g_capture = cvCreateFileCapture(argv[1]); //获取视频总帧数 int frames = (int) cvGetCaptureProperty(g_capture,CV_CAP_PROP_FRAME_COUNT); if(frames != 0) { //创建滚动条:名称,所在窗体,全局变量指针,总帧数,回调函数。 cvCreateTrackbar( "Position", "Example3", &g_slider_position, frames, onTrackbarSlide ); } IplImage* frame; //播放视频 while(1) { frame = cvQueryFrame(g_capture); if(!frame) break; cvShowImage("Example3",frame); char c = cvWaitKey(200); if(c == 27) break; } cvReleaseCapture(&g_capture); cvDestroyWindow("Example3"); return 0; }
- 编译过程和运行
xbw@xbw-VirtualBox:~/code/cv_test$ gcc 1_test.c `pkg-config --cflags --libs opencv`
xbw@xbw-VirtualBox:~/code/cv_test$ ./a.out tree.avi
- 要点
案例只有生成进度条和回调的功能,没有实现进度条随帧数改变,读取的总帧数也有错误。实际只有几十帧,而显示了四百多帧。并不太了解怎么修改,等后面详细学习再看看吧。
应该有一个刷新滚动条位置的函数,试过给全局变量自增,但是没有效果。
四,简单图像处理
- 程序
-
#include"cv.h" #include"highgui.h" void example(IplImage* image) { cvNamedWindow("Example4-in",CV_WINDOW_AUTOSIZE); cvNamedWindow("Example4-out",CV_WINDOW_AUTOSIZE); cvShowImage("Example4-in",image); //分配输出图片的内存空间 IplImage* out = cvCreateImage( cvGetSize(image), IPL_DEPTH_8U, 3 ); //平滑函数 cvSmooth(image,out,CV_GAUSSIAN,3,3,0,0); cvShowImage("Example4-out",out); cvReleaseImage(&out); cvWaitKey(0); cvDestroyWindow("Example4-in"); cvDestroyWindow("Example4-out"); } int main(int argc,char** argv) { IplImage* img = cvLoadImage(argv[1],1); example(img); return 0; }
- 编译过程和运行
xbw@xbw-VirtualBox:~/code/cv_test$ gcc 1_test.c `pkg-config --cflags --libs opencv`
xbw@xbw-VirtualBox:~/code/cv_test$ ./a.out org.jpg
- 要点
函数cvSmooth(image,out,CV_GAUSSIAN,3,3,0,0);在原书中只有5个参数,查阅头文件定义有7个。似乎opencv几个版本差异并不小,而且做不到向后兼容。
五,读取摄像头视频
- 程序
-
#include"highgui.h" //和读取视频没有区别,都通过CvCapture指针 int main(int argc,char** argv) { cvNamedWindow("Example2",CV_WINDOW_AUTOSIZE); CvCapture* capture; //-1为随机选择一个相机录像 capture = cvCreateCameraCapture(-1); IplImage* frame; while(1) { frame = cvQueryFrame(capture); if(!frame) break; cvShowImage("Example2",frame); char c = cvWaitKey(30); if(c == 27) break; } cvReleaseCapture(&capture); cvDestroyWindow("Example2"); return 0; }
- 编译过程和运行
xbw@xbw-VirtualBox:~/code/cv_test$ gcc 1_test.c `pkg-config --cflags --libs opencv`
xbw@xbw-VirtualBox:~/code/cv_test$ ./a.out
- 要点
在VirtualBox虚拟机下,最开始无法读取摄像头。原来以为是驱动问题,通过V4L2调取UVC摄像头,能读取到但无法读取流。后来证明是虚拟机的问题。需要下载VirtualBox Extension Pack,就是usb增强包,用USB3.0可以正常读取。
总结
第二章还有些练习,不过大体上都是对于highgui.h库的运用。运行完上述例子,大体的逻辑如下:
- 命名窗口
- 创建图像/视频指针
- 读取图像/视频帧,分配内存
- 在窗口中显示
- 等待按键操作
- 销毁窗口
- 释放图像/视频指针
值得一提的就是,没有我想象中那么复杂的摄像头驱动设置,V4L2驱动框架调用video0的UVC摄像头,很自然的就完成了。我觉得后续难点是图形学的相关知识,对于图像的通道什么的属性完全没了解到话,根本看不下去。很多问题的解决方法都是线性代数的术语,要重新补一补。