《学习OpenCV》随笔——第2章 OpenCV入门
《学习OpenCV》随笔——第2章 OpenCV入门
第一章部分由于大致属于介绍OpenCV的部分,其中着重强调Intel在这方面所做的贡献。诚然,开源者都有一颗博爱之心和虚心的、积极进取的心态吧。
从第二章开始,这本书才开始有了一定的可以写的东西。写博客的目的还是老样子——以写促学。
在上代码之前,还需要强调一下,在OpenCV的官网下载的OpenCV 3.0beta版本中,有一些文件(库)的文件组织结构通2.x版本有所出入,导致网上教程有一定的不同。这里一定注意。
笔者于2015年5月25日01:59注
在这里,我们要注意一些地方:
1、在Qt 中使用,如果使用MSVC编译器,则具体编译步骤远没有MingWs的复杂。只要系统路径注意一些,然后再pro文件中加入
INCLUDEPATH+=E:\opencv2.49\opencv\build\include\opencv2\
E:\opencv2.49\opencv\build\include\opencv\
E:\opencv2.49\opencv\build\include
CONFIG(release,debug|release)
{
LIBS+=E:\opencv2.49\opencv\build\x86\vc11\lib\opencv_calib3d249.lib\
E:\opencv2.49\opencv\build\x86\vc11\lib\opencv_contrib249.lib\
E:\opencv2.49\opencv\build\x86\vc11\lib\opencv_core249.lib\
E:\opencv2.49\opencv\build\x86\vc11\lib\opencv_features2d249.lib\
E:\opencv2.49\opencv\build\x86\vc11\lib\opencv_flann249.lib\
E:\opencv2.49\opencv\build\x86\vc11\lib\opencv_gpu249.lib\
E:\opencv2.49\opencv\build\x86\vc11\lib\opencv_highgui249.lib\
E:\opencv2.49\opencv\build\x86\vc11\lib\opencv_imgproc249.lib\
E:\opencv2.49\opencv\build\x86\vc11\lib\opencv_legacy249.lib\
E:\opencv2.49\opencv\build\x86\vc11\lib\opencv_ml249.lib\
E:\opencv2.49\opencv\build\x86\vc11\lib\opencv_objdetect249.lib\
E:\opencv2.49\opencv\build\x86\vc11\lib\opencv_ts249.lib\
E:\opencv2.49\opencv\build\x86\vc11\lib\opencv_video249.lib
}
CONFIG(debug,debug|release)
{
LIBS+=E:\opencv2.49\opencv\build\x86\vc11\lib\opencv_calib3d249d.lib\
E:\opencv2.49\opencv\build\x86\vc11\lib\opencv_contrib249d.lib\
E:\opencv2.49\opencv\build\x86\vc11\lib\opencv_core249d.lib\
E:\opencv2.49\opencv\build\x86\vc11\lib\opencv_features2d249d.lib\
E:\opencv2.49\opencv\build\x86\vc11\lib\opencv_flann249d.lib\
E:\opencv2.49\opencv\build\x86\vc11\lib\opencv_gpu249d.lib\
E:\opencv2.49\opencv\build\x86\vc11\lib\opencv_highgui249d.lib\
E:\opencv2.49\opencv\build\x86\vc11\lib\opencv_imgproc249d.lib\
E:\opencv2.49\opencv\build\x86\vc11\lib\opencv_legacy249d.lib\
E:\opencv2.49\opencv\build\x86\vc11\lib\opencv_ml249d.lib\
E:\opencv2.49\opencv\build\x86\vc11\lib\opencv_objdetect249d.lib\
E:\opencv2.49\opencv\build\x86\vc11\lib\opencv_ts249d.lib\
E:\opencv2.49\opencv\build\x86\vc11\lib\opencv_video249d.lib
}
这里的E:\opencv2.49改成自己的路径即可。原文来自http://ask.csdn.net/questions/26810,致谢!
2、如果出现以下问题,请查看
http://www.cnblogs.com/csulennon/p/3775980.html 这个问题在vs12中出现过,有一定的实用性。
我们在配置完环境后,就要进行一个引导部分。这里我们使用了一个简短的例子:
#include<opencv\highgui.h> //原书使用版本和我的不一样,文件位置有出入 int main() { IplImage *img=cvLoadImage("1.png"); cvNamedWindow("Example1",CV_WINDOW_AUTOSIZE); cvShowImage("Example1",img); cvWaitKey(0); cvReleaseImage(&img); cvDestroyWindow("Example1"); }
嗯,这个简短的程序看起来还不错,那是什么意思呢?我们扔掉书本,看一下手册(我的版本是2.49,手册是2.43的)里面的解释吧。
The IplImage is taken from the Intel Image Processing Library, in which the format is native. OpenCV only supports a subset of possible IplImage formats, as outlined in the parameter list above.
大致意思就是说IplImage这个类型来自于Intel 图像处理库。OpenCV这里用的是intel的IplImage格式的子集。
Loads an image from a file.
- C++: Mat imread(const string& filename, int flags=1 )¶
- Python: cv2.imread(filename[, flags]) → retval¶
- C: IplImage* cvLoadImage(const char* filename, int iscolor=CV_LOAD_IMAGE_COLOR )¶
- C: CvMat* cvLoadImageM(const char* filename, int iscolor=CV_LOAD_IMAGE_COLOR )¶
- Python: cv.LoadImage(filename, iscolor=CV_LOAD_IMAGE_COLOR) → None¶
- Python: cv.LoadImageM(filename, iscolor=CV_LOAD_IMAGE_COLOR) → None¶
- 下面的红字挺重要的,其中提及了grayscale,这个确实不赖,这里就不上图对比了。
-
Parameters: - filename – Name of file to be loaded.
- flags –
Flags specifying the color type of a loaded image:
- CV_LOAD_IMAGE_ANYDEPTH - If set, return 16-bit/32-bit image when the input has the corresponding depth, otherwise convert it to 8-bit.
- CV_LOAD_IMAGE_COLOR - If set, always convert image to the color one
- CV_LOAD_IMAGE_GRAYSCALE - If set, always convert image to the grayscale one
- >0 Return a 3-channel color image.
-
Note
In the current implementation the alpha channel, if any, is stripped from the output image. Use negative value if you need the alpha channel.
- =0 Return a grayscale image.
- <0 Return the loaded image as is (with alpha channel).
The function imread loads an image from the specified file and returns it. If the image cannot be read (because of missing file, improper permissions, unsupported or invalid format), the function returns an empty matrix ( Mat::data==NULL ). Currently, the following file formats are supported:
- Windows bitmaps - *.bmp, *.dib (always supported)
- JPEG files - *.jpeg, *.jpg, *.jpe (see the Notes section)
- JPEG 2000 files - *.jp2 (see the Notes section)
- Portable Network Graphics - *.png (see the Notes section)
- Portable image format - *.pbm, *.pgm, *.ppm (always supported)
- Sun rasters - *.sr, *.ras (always supported)
- TIFF files - *.tiff, *.tif (see the Notes section)
Note
下面这一条红字是好东西,它是根据内容来进行格式决定,而不是根据扩展名。
- The function determines the type of an image by the content, not by the file extension.
- On Microsoft Windows* OS and MacOSX*, the codecs shipped with an OpenCV image (libjpeg, libpng, libtiff, and libjasper) are used by default. So, OpenCV can always read JPEGs, PNGs, and TIFFs. On MacOSX, there is also an option to use native MacOSX image readers. But beware that currently these native image loaders give images with different pixel values because of the color management embedded into MacOSX.
- On Linux*, BSD flavors and other Unix-like open-source operating systems, OpenCV looks for codecs supplied with an OS image. Install the relevant packages (do not forget the development files, for example, “libjpeg-dev”, in Debian* and Ubuntu*) to get the codec support or turn on the OPENCV_BUILD_3RDPARTY_LIBS flag in CMake.
Note
In the case of color images, the decoded images will have the channels stored in B G R order.
cvNameWindow函数的介绍是:
Creates a window.
- C++: void namedWindow(const string& winname, int flags=WINDOW_AUTOSIZE )¶
- Python: cv2.namedWindow(winname[, flags]) → None¶
- C: int cvNamedWindow(const char* name, int flags=CV_WINDOW_AUTOSIZE )¶
- Python: cv.NamedWindow(name, flags=CV_WINDOW_AUTOSIZE) → None¶
-
Parameters: - name – Name of the window in the window caption that may be used as a window identifier.
- flags –
Flags of the window. The supported flags are:
- WINDOW_NORMAL If this is set, the user can resize the window (no constraint).
- WINDOW_AUTOSIZE If this is set, the window size is automatically adjusted to fit the displayed image (see imshow() ), and you cannot change the window size manually.
- WINDOW_OPENGL If this is set, the window will be created with OpenGL support.
这里列举了三种语言的函数声明形式,大致差别不大。这里形参表给了两个参数,第一参数是name,即窗口名称。第二个略微有些意思,在一般情形下是三个宏。
The function namedWindow creates a window that can be used as a placeholder for images and trackbars. Created windows are referred to by their names.
If a window with the same name already exists, the function does nothing.
You can call destroyWindow() or destroyAllWindows() to close the window and de-allocate any associated memory usage. For a simple program, you do not really have to call these functions because all the resources and windows of the application are closed automatically by the operating system upon exit.
Note
在这里,文档中提的相当的清晰,窗口是以名称作为区别的,如果窗口重名了,那后者就啥都不做。
Qt backend supports additional flags:
- CV_WINDOW_NORMAL or CV_WINDOW_AUTOSIZE: CV_WINDOW_NORMAL enables you to resize the window, whereas CV_WINDOW_AUTOSIZE adjusts automatically the window size to fit the displayed image (see imshow() ), and you cannot change the window size manually.
- CV_WINDOW_FREERATIO or CV_WINDOW_KEEPRATIO: CV_WINDOW_FREERATIO adjusts the image with no respect to its ratio, whereas CV_WINDOW_KEEPRATIO keeps the image ratio.
- CV_GUI_NORMAL or CV_GUI_EXPANDED: CV_GUI_NORMAL is the old way to draw the window without statusbar and toolbar, whereas CV_GUI_EXPANDED is a new enhanced GUI.
By default, flags == CV_WINDOW_AUTOSIZE | CV_WINDOW_KEEPRATIO | CV_GUI_EXPANDED
还顺道提及了一下Qt这方面,确实有点意思了。看来也顾及到跨平台方面了。Qt中有了一些变化,但是感觉基本没啥。
cvShowImage这个函数没啥好讲的,而且手册上几乎一笔带过。
我们还是得看一下cvWaitKey这个函数。其实主要看一下这两个note
Note
This function is the only method in HighGUI that can fetch and handle events, so it needs to be called periodically for normal event processing unless HighGUI is used within an environment that takes care of event processing.
Note
The function only works if there is at least one HighGUI window created and the window is active. If there are several HighGUI windows, any of them can be active.
这个例子就这么简单一说吧,连篇累牍的英文确实令人厌烦,但是这个手册远远比我写的文档好太多。而且这个手册的详尽程度不逊色于Qt。
——————————————————————————————————————————我是分割线————————————————————————————————————————
下面一个程序及时AVI视频播放了,这里的代码完全可以套在例如RMVB这样的格式的视频播放,前提是这种格式在你的系统里面应当有解码器。
1 #include<opencv\highgui.h> 2 int main() 3 { 4 cvNamedWindow("example2",CV_WINDOW_AUTOSIZE); 5 CvCapture*capture=cvCreateFileCapture("2.avi"); 6 IplImage* frame=0; 7 while(1) 8 { 9 frame=cvQueryFrame(capture); 10 if(!frame) 11 break; 12 cvShowImage("example2",frame); 13 char c=cvWaitKey(33); 14 if(c==27) 15 break; 16 } 17 cvReleaseCapture(&capture); 18 cvDestroyWindow("example2"); 19 } 20 }
这里还是要从手册里面来说一下代码的意思吧,毕竟这本书还是说的笼统的厉害了点。
第5行中cvCapture作为一个结构体类型,在手册中没有提及具体成员,这里我们引用“CvCapture是一个结构体,用来保存图像捕获的信息,就像一种数据类型(如 int,char等)只是存放的内容不一样,在OpenCv中,它最大的作用就是处理视频时(程序是按一帧一帧读取),让程序读下一帧的位 置,CvCapture结构中,每获取一帧后,这些信息都将被更新,获取下一帧回复。 ”(引用完,来自http://blog.csdn.net/sysstc/article/details/25126551,致谢),上面说的这些大致能够描述这个类型的适用范围。cvCreateFileCapture这个函数手册中也没有讲什么。
第9行中的cvQueryFrame函数在手册中是这样描述的:
The methods/functions combine VideoCapture::grab() and VideoCapture::retrieve() in one call. This is the most convenient method for reading video files or capturing data from decode and return the just grabbed frame. If no frames has been grabbed (camera has been disconnected, or there are no more frames in video file), the methods return false and the functions return NULL pointer.
Note
OpenCV 1.x functions cvRetrieveFrame and cv.RetrieveFrame return image stored inside the video capturing structure. It is not allowed to modify or release the image! You can copy the frame using cvCloneImage() and then do whatever you want with the copy
13行有一个巧妙地应用。这里cvWaitKey函数的使用有两个好处:1、起到了调节播放帧数的作用。2、起到停止播放的作用。
由于这个函数位置位于while(1)这个块内,通过不断加载每一帧图片来进行电影播放,但是如果任由其加载而不进行规范,则会影响效果。
The function waitKey waits for a key event infinitely (when delay<0 ) or for delay milliseconds, when it is positive. Since the OS has a minimum time between switching threads, the function will not wait exactly delay ms, it will wait at least delay ms, depending on what else is running on your computer at that time. It returns the code of the pressed key or -1 if no key was pressed before the specified time had elapsed.
Note
This function is the only method in HighGUI that can fetch and handle events, so it needs to be called periodically for normal event processing unless HighGUI is used within an environment that takes care of event processing.
Note
The function only works if there is at least one HighGUI window created and the window is active. If there are several HighGUI windows, any of them can be active.
上面提及了这个是按照线程调度的时钟来进行的。因此最少会间隔delay ms。