在学习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摄像头,很自然的就完成了。我觉得后续难点是图形学的相关知识,对于图像的通道什么的属性完全没了解到话,根本看不下去。很多问题的解决方法都是线性代数的术语,要重新补一补。