Ubuntu下的Opencv的安装与初步使用
一、认识 OpenCV
开源计算机视觉(OpenCV)是一个主要针对实时计算机视觉的编程函数库。
OpenCV的应用领域包括:
- 2D和3D功能工具包
- 运动估计
- 面部识别系统
- 手势识别
- 人机交互
- 移动机器人
- 动作理解
- 物体识别
- 分割和识别
- 实体影像立体视觉:来自两个摄像机的深度感知
- 运动中的结构(SFM)
- 运动跟踪
- 增强现实
- 为了支持上述一些领域,OpenCV包括一个统计机器学习库,其中包含:
- 提升(Boosting)
- 决策树学习
- 梯度提升树
- 期望最大化算法
- k最近邻算法
- 朴素贝叶斯分类器
- 人工神经网络
- 随机森林
- 支持向量机(SVM)
- 深层神经网络(DNN)
二、安装 OpenCV
2.1
下载 OpenCV 3.4.11 数据包
国内快速下载地址:https://www.bzblog.online/wordpress/index.php/2020/03/09/opencvdownload/
2.2

2.3

2.4
unzip opencv-3.4.11.zip

2.5
使用 cmake 安装 opencv
首先进入解压后的文件夹:opencv-3.4.11
cd opencv-3.4.11
首先进入 root 用户,并更新一下。
sudo su sudo apt-get update

sudo apt-get install cmake

sudo apt-get install build-essential libgtk2.0-dev libavcodec-dev libavformat-dev libjpeg.dev libtiff5.dev libswscale-dev libjasper-dev
接下来创建 build 文件夹
mkdir build
然后进入我们创建的文件夹:build
cd build
使用 cmake 编译参数,或者使用第二条默认参数,都可以的。
cmake -D CMAKE_BUILD_TYPE=Release -D CMAKE_INSTALL_PREFIX=/usr/local ..
cmake ..

2.6
使用 make 创建编译
仍然是在 build 文件夹下进行。
sudo make #单线程编译:sudo make ,这会等待比较长的时间,如果你想更快编译完,可以使用命令:sudo make -j4 ,而 -j4 表示使用 4 个线程进行编译

编译完成

2.7安装
sudo make install

安装过程中没有报错,即可安装完成。
三、配置环境
修改 opencv.conf 文件,打开后的文件是空的,添加 opencv 库的安装路径:/usr/local/lib
sudo gedit /etc/ld.so.conf.d/opencv.conf

保存后会看到之前的警告信息,不用理睬。
sudo ldconfig
配置 bash ,修改 bash.bashrc 文件
sudo gedit /etc/bash.bashrc
在文件末尾插入
PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig
export PKG_CONFIG_PATH

source /etc/bash.bashrc

出现提示则安装成功
四、在安装过程中需要注意的问题(请先看此处)
安装过程中 需要注意的是留心是否进入了文件目录的问题,如果没有进入opencv的文件目录 在进行 make操作时会提示没有无法定位软件包“libjasper-dev“的问题,遇见这种情况有两种:①下载的软件包有问题②没有进入相应的文件目录。第二点尤其需要注意 不然会花费大量的时间去寻找问题,文章结尾处会放初一些博客的链接,是我解决问题的中看到的一些文章,可以供大家参考。
五、初试Opencv
mkdir cv2 cd cv2
vim test1.cpp

然后输入如下的代码
#include <opencv2/highgui.hpp> #include <opencv2/opencv.hpp> using namespace cv; using namespace std; int main(int argc, char** argv) { CvPoint center; double scale = -3; IplImage* image = cvLoadImage("lena.jpg"); argc == 2? cvLoadImage(argv[1]) : 0; cvShowImage("Image", image); if (!image) return -1; center = cvPoint(image->width / 2, image->height / 2); for (int i = 0;i<image->height;i++) for (int j = 0;j<image->width;j++) { double dx = (double)(j - center.x) / center.x; double dy = (double)(i - center.y) / center.y; double weight = exp((dx*dx + dy*dy)*scale); uchar* ptr = &CV_IMAGE_ELEM(image, uchar, i, j * 3); ptr[0] = cvRound(ptr[0] * weight); ptr[1] = cvRound(ptr[1] * weight); ptr[2] = cvRound(ptr[2] * weight); } Mat src;Mat dst; src = cvarrToMat(image); cv::imwrite("test.png", src); cvNamedWindow("test",1); imshow("test", src); cvWaitKey(); return 0; }
编译文件:
执行以下命令:
g++ test1.cpp -o test1 `pkg-config --cflags --libs opencv`
#–cflags用来指定程序在编译时所需要头文件所在的目录;–libs是指定程序在链接时所需要的动态链接库的目录
之后我们在同文件目录下,放入一张名为lena的图片,然后运行

会看到成功的显示了lena图
关于lena图的一些故事
该图原本是刊于1972年11月号花花公子杂志上的一张裸体插图照片的一部分,这期花花公子也是历年来最畅销的一期,销量达7,161,561本。1973 年6月,美国南加州大学的信号图像处理研究所的一个助理教授和他的一个研究生打算为了一个学术会议找一张数字照片,而他们对于手头现有成堆"无聊"照片感到厌烦。事实上他们需要的是一个人脸照片,同时又能让人眼前一亮。这时正好有人走进实验室,手上带着一本当时的花花公子杂志,结果故事发生了……而限于当时实验室设备和测试图片的需要,lenna的图片只抠到了原图的肩膀部分。
图中人为瑞典模特儿 Lena Soderberg。现在被广泛使用的英文化名字"Lenna"最初是由花花公子杂志发表此照片时命名的,以方便英语读者近似正确地读出瑞典语中 "Lena"的发音。Lena Soderberg 女士现在仍住在她的家乡瑞典,拥有一个有三个孩子的家庭,并且在国家酒类专卖局工作。在1988年的时候,她接受了瑞典一些计算机相关出版社的访问,她对 于她的照片有这样的奇遇感到非常的惊奇与兴奋。这是她首次得知她的照片被应用在计算机行业。Lena Soderberg于1997年被邀请为嘉宾,参加了数字图像科学技术50周年学术会议。在该会议上,Lenna成了最受欢迎的人之一,她做了关于自己介 绍的简要发言,并被无数的fans索取签名。
莱娜图在图像压缩算法是最广泛应用的标准测试图——她的脸部与裸露的肩部已经变成了事实 上的工业标准。然而,这张图像的使用也引起了一些争议。一些人担心它的色情内容;《花花公子》杂志曾经威胁要起诉对莱娜图未经授权的使用。不过这家杂志已经放弃了这种威胁,取而代之的是鼓励因为公众利益使用莱娜图。戴维·C·蒙森(David C.Munson),IEEE图像处理汇刊(IEEE Transactions on Image Processing)的主编, 在1996年1月引用了两个原因来说明莱娜图在科研领域流行的原因:1.该图适度的混合了细节、平滑区域、阴影和纹理,从而能很好的测试各种图像处理算法。2.Lenna是个美女,对于图象处理界的研究者(大部分都是男性)来说,美女图可以有效的吸引他们来做研究。两张照片对比之下,莱娜的容貌虽已然衰老,但映射出的则是人工智能在计算机视觉领域走过了 46 年的发展。要知道,上世纪 60 年代,达特茅斯会议刚刚掀起第一波人工智能浪潮。直到 2012 年,Geoffery Hinton 团队参与的 ImageNet 竞赛,使用 CNN 模型以超过第二名 10 个百分点的成绩夺得当年竞赛的冠军。如今,深度学习、人工智能在图像处理领域正逐步深入的研究和应用。
六、播放视频那些事
获得摄像头权限
使用快捷键 Win + R ,输入 services.msc ,并回车。

找到 VMware USB Arbitration S*服务,确保启动了。

点击 “ 虚拟机 ” ,然后点击 设置(S)

选择 “ USB控制器 ” ,将 “ USB兼容性 ” 设置为 “ USB 3.1 ” ,并点击确定。
选择 “ 虚拟机 ” ,再选择 “ 可移动设备 ” ,再选择 “ Microdia Intergrated_Webcam_HD(不同电脑可能摄像头名称不同) ” ,最后点击 “ 连接 ” ,再弹出的窗口内点击 “ 确定 ” 。

虚拟机右下角这个摄像头图标有个小绿点,则连接成功。

播放视频
关于需要播放视频的提前准备工作如下
安装snapd,终端命令: sudo apt-get install snapd 安装ffmpeg: sudo snap install ffmpeg sudo add-apt-repository ppa:jonathonf/ffmpeg-4 sudo apt-get update sudo apt-get install ffmpeg 查看ffmpeg: ff[TAB][TAB]
使用ffmpeg打开mp4视频文件:
ffplay -autoexit filename.mp4
如果安装完后提示:video现缺少mpeg4 blabla h.246 decoder
输入 sudo snap install ffmpeg
创建一个 test2.cpp 文件。
vim test.cpp
将以下代码复制粘贴进去
#include <opencv2/opencv.hpp> using namespace cv; int main() { //从摄像头读取视频 VideoCapture capture("WLH.mp4"); //循环显示每一帧 while(1){ Mat frame;//定义一个Mat变量,用于存储每一帧的图像 capture >> frame;//读取当前帧 if(frame.empty())//播放完毕,退出 break; imshow("读取视频帧",frame);//显示当前帧 waitKey(30);//掩饰30ms } system("pause"); return 0; }
代码讲解:
- 如果语句:VideoCapture capture(0),后面的参数设置为 0 ,则从摄像头读取视频并循环显示每一帧;如果设置为一个视频的文件名,比如:man.mp4 ,则会将视频读取并循环显示每一帧。
- while 循环体中的 Mat 数据结构其实是一个点阵,对应图像上的每一个点,点的集合形成了一帧图像,有关 Mat 详解请看:OpenCV中Mat数据结构
- 语句:waitKey(30) ,中的参数单位是 ms 毫秒,也就是每一帧间隔 30 ms ,该语句时不能删除的,否则会执行错误,无法播放视频或录制视频。
准备一个小视频,我这里准备了 罗曼卓耶弹的王力宏的唯一作为播放视频

编译一下
g++ test2.cpp -o test2 `pkg-config --cflags --libs opencv`

关于如何退出:切换到终端 按下ctrl+c结束程序!!
接下来我们解析一下如何解决这么不人性化的问题

我对代码进行了一些修改
加入的部分如下
if( (key = waitKey(2)) !=-1)//如果2ms内有按键 有返回值key { printf("press key:%c\n",key); if(key == 'q') break; } }
按下q之后 可以返回你的输出

在代码中设置的字符‘q’按下后为退出,可以改变代码中的字符,改为你喜欢的按键然后退出。
过程中遇到的一些问题
有可能会提示Failed to load module "canberra-gtk-module" 此时我们需要使用 sudo apt-get install libcanberra-gtk-module 命令 解决问题
一些问题的解析
Q:如果要求打开你硬盘上一个视频文件来播放,如何修改?
A:找到文件的绝对路径位置
例如
VideoCapture capture("filepath.mp4");
Q:Mat是一个什么数据结构?
A:
OpenCV从2001年开始发展,在最初使用的是c语言,使用的是IplImage数据结构来存储图像,但是最大的问题需要手动申请释放内从( manual memory management),从OpenCV2.0开始,开始使用C++接口的Mat,这是自动分配和释放内存的(automatic memory management)。
Mat有两部分组成
- 头部:存储方式、图像大小等信息,头部的大小是一个常量(constant)
- 数据块:图像像素的值(按行顺序存储)
- NOTE1:大部分拷贝Mat,如拷贝构造、赋值操作,只是拷贝头部信息,他们指向同一个数据块,不同对象对其做操作,会影响到其他对象。如果想进行深拷贝用
- cv::Mat::copyTo 和cv::Mat::clone 方法
NOTE2:多个头部指向同一个Matrix,那么谁来对其进行销毁:最后一个使用的对象,OpenCV内部有引用的计数机制 (reference counting mechanism),当增加一个对象(只复制一个头部指向Matrix)counter+1;如果一个对象销毁,counter-1。最后一个对象对Matrix进行回收。
Q: 为什么一定要加一句waitKey延时代码,删除它行不行?
A:waitKey()与waitKey(0),都代表无限等待,waitKey函数的默认参数就是int delay = 0,故这俩形式本质是一样的。waitKey(n),等待n毫秒后,关闭显示的窗口。
七、录制视频
同上步骤,创建一个 test3.cpp
代码如下:
#include<iostream> #include <opencv2/opencv.hpp> #include<opencv2/core/core.hpp> #include<opencv2/highgui/highgui.hpp> using namespace cv; using namespace std; int main() { //打开电脑摄像头 VideoCapture cap(0); if (!cap.isOpened()) { cout << "error" << endl; waitKey(0); return 0; } //获得cap的分辨率 int w = static_cast<int>(cap.get(CV_CAP_PROP_FRAME_WIDTH)); int h = static_cast<int>(cap.get(CV_CAP_PROP_FRAME_HEIGHT)); Size videoSize(w, h); VideoWriter writer("RecordVideo.avi", CV_FOURCC('M', 'J', 'P', 'G'), 25, videoSize); Mat frame; int key;//记录键盘按键 char startOrStop = 1;//0 开始录制视频; 1 结束录制视频 char flag = 0;//正在录制标志 0-不在录制; 1-正在录制 while (1) { cap >> frame; key = waitKey(100); if (key == 32)//按下空格开始录制、暂停录制 可以来回切换 { startOrStop = 1 - startOrStop; if (startOrStop == 0) { flag = 1; } } if (key == 27)//按下ESC退出整个程序,保存视频文件到磁盘 { break; } if (startOrStop == 0 && flag==1) { writer << frame; cout << "recording" << endl; } else if (startOrStop == 1) { flag = 0; cout << "end recording" << endl; } imshow("picture", frame); } cap.release(); writer.release(); destroyAllWindows(); return 0; }
按下空格键后会开始录制,同样的需要用ctrl+c中止,我们同样可以通过修改代码来完成一些人性化的操作

生成了record文件,同时获取了视频。
心得体会
Opencv的安装和使用过程真的非常非常的艰难和繁琐,在过程中遇到了很多的问题。例如ubuntu无法直接播放MP4 需要安装很多的软件来支持视频的播放,以及过程中遇到了一些BUG之类的难题,但是解决完问题之后的成就感是无与伦比的,能坚持从开始到完成是一次挑战,更是一次成长,在这次的过程中学到了很多东西,以及感受到了使用Opencv的乐趣。
参考链接
https://blog.csdn.net/ssj925319/article/details/109231145
https://blog.csdn.net/weixin_41948344/article/details/88762843
https://blog.csdn.net/chichu261/article/details/84981412
https://blog.csdn.net/qq_36512295/article/details/102785750
浙公网安备 33010602011771号