opencv的运用
. 编写一个打开图片进行特效显示的代码 test1.cpp(见opencv编程参考资料 );
注意gcc编译命令: gcc test1.cpp -o test1 pkg-config --cflags --libs opencv
1)请解释这条编译命令,它是如何获得opencv头文件、链接lib库文件的路径的?
2)改用make+makefile方式编译 上述程序(用变量命名格式写makefile文件,并包括 clean选项)
首先创建一个代码存放文件夹 code ,然后进入文件夹中
创建一个 test1.cpp 文件。
在用同文件夹下准备一张图片,文件名为:lena.jpg
test1.cpp 文件内容如下:
打开本地视频播放
编译与运行
gcc 编译
gcc 编译命令如下:
编译与运行
gcc 编译
gcc 编译命令如下:
sudo g++ test1.cpp -o test1 `pkg-config --cflags --libs opencv`
我们是如何获取 opencv 头文件的,又是如何 lib 库文件路径的?
在上面的编译命令中,我们其实使用了一个工具 " pkg-config " ,主要有以下几个功能:
1.检查库的版本号,如果需要的库不满足要求,会打印出错误消息,避免链接错误版本的库文件,这也就是我们大多时候报错的原因
2.获得编译预处理参数,如宏定义,头文件的位置
3.获得链接参数,如库及依赖的其他库的位置,文件名及其他一些链接参数
4.自动加入所依赖的其他库
所有有了这个工具之后我们的编译就很方便了(不过在此之前你要确保你安装的OpenCV的安装链接库文件的目录下有一个 pkgconfig 文件夹,在该文件夹里面有个 opencv.pc 的文件,其实这就是 pkg-config 下 OpenCV 的配置文件)
使用 pkg-config 时,选项 --cflags 它是用来指定程序在编译时所需要头文件所在的目录,选项 --libs 则是指定程序在链接时所需要的动态链接库的目录
在上述编译过程中,实际上应该如下
gcc main.c -I/usr/local/include/opencv -I/usr/local/include -L/usr/local/lib -lopencv_calib3d -lopencv_contrib -lopencv_core -lopencv_features2d -lopencv_flann -lopencv_gpu -lopencv_highgui -lopencv_imgproc -lopencv_legacy -lopencv_ml -lopencv_nonfree -lopencv_objdetect -lopencv_ocl -lopencv_photo -lopencv_stitching -lopencv_superres -lopencv_ts -lopencv_video -lopencv_videostab -lrt -lpthread -lm -ldl
Makefile 编译
建立 makefile 文件内容如下:
.PHONY:clean
CXX = g++
LIBS = `pkg-config --libs opencv`
CFLAGS = `pkg-config --cflags opencv`
CPPCFLAGS = -g -std = c++11 -Werror
SRCS = test1.cpp
TARGET = test1.out
OBJS = test1.o
# 编译生成可执行文件
$(TARGET): $(OBJS)
@echo "Start Compiling……"
@echo $(CXX)
$(CXX) $(INC) $(CPPFLAGS) $(OBJS) -O $(TARGET) $(LIBS)
@echo "Compile Done!"
# 下面是顺序编译生成 .o 文件
# 每个 .c 文件都会编译生成对应的 .o 文件
# < 表示目标依赖表中的第一个依赖文件; @ 表示生成的对应的目标文件
$(OBJS):%.o:%.c
$(CXX) $(INC) $(CPPFLAGS) -c $< -o $@
clean:
-rm -r *.o $(TARGET)
编译指令如下:
make
# 编译运行后,应删除编译产生文件,以便后续再次编译,删除命令如下:
make clean
运行
直接运行可执行程序,成功调用电脑摄像头,如下图:
变量介绍
Mat
Mat 是一个类,使用的非常广泛,下面只介绍他的默认构造函数
默认构造函数
cv::Mat::Mat()
默认构造函数:生成一个矩阵并由 OpenCV 提供的函数(一般是 Mat::create() 和 cv::imread() )来分配储存空间。
Mat 类可以分为两个部分:矩阵头和指向像素数据的矩阵指针
矩阵头:包括数字图像的矩阵尺寸、存储方法、存储地址和引用次数等,矩阵头的大小是一个常数,不会随着图像的大小而改变,但是保存图像像素数据的矩阵则会随着图像的大小而改变,通常数据量会很大,比矩阵头大几个数量级。这样,在图像复制和传递过程中,主要的开销是由存放图像像素的矩阵而引起的。因此,OpenCV 使用了引用次数,当进行图像复制和传递时,不再复制整个 Mat 数据,而只是复制矩阵头和指向像素矩阵的指针,例如:
CV::Mat a
a = CV::imread("图片路径")
CV::Mat b = a
上面的a,b有各自的矩阵头,但是其矩阵指针指向同一个矩阵,也就是其中任何一个改变了矩阵数据都会影响另外一个。那么,多个 Mat 共用一个矩阵数据,最后谁来释放矩阵数据呢?
这就是引用计数的作用,当 Mat 对象每被复制一次时,就会将引用计数加1,而每销毁一个 Mat 对象(共用同一个矩阵数据)时引用计数会被减 1,当引用计数为 0 时,矩阵数据会被清理。
通俗一点来说,就是通过矩阵来读入一个图片的所有像素,然后在显示的时候,在通过矩阵还原图片的像素点,达到显示图片的效果
waitkey
waitKey函数用于显示的延迟。例如,waitKey(0) 将无限显示窗口,直到按下任意按键退出延迟事件(适用于显示图像)。如果 delay 大于0,例如,waitKey(30) 将每隔至少 30ms 显示视频的一帧图像(适用于显示视频帧),如果要按键退出,则需要将 waitKey(30) 与一个按键值(ASCII码)比较。
waitKey() 函数的功能就是在不断刷新图像,频率为 delay ,单位是 ms ,返回值为当前键盘按下的值,没有按键时返回 -1
显示图片和视频时,会在 imshow()时,通常会在后面加上 while(cvWaitKey(n)==key) 为大于等于 0 的数即可,那么程序将在此处循环运行直到按键响应为 key 时之后继续,如果没有设置 key 值,只是设置了 waitKey ,则就会一直显示视频界面,不一会退出
delay : 为 0 时,则会一直显示这一帧,“delay”,在显示视频和摄像头时有用,用于设置在显示完一帧图像后程序等待“delay" ms 再显示下一帧视频
如果程序想响应某个按键,可利用 if(cvWaitKey(1)==Keyvalue);经常程序里面出现 if( cvWaitKey(10) >= 0 ) 是说 10ms 中按任意键进入此 if 块
注意:在 imshow 之后如果没有 waitKey 语句则不会正常显示图像。