每一个程序背后都站着一堆优秀的代码库。本文主要叙述通过学习opencv图像库编程,了解如何借助第三方库函数完成一个综合程序设计。
OpenCV 是一个基于 Apache2.0 许可(开源)发行的跨平台计算机视觉和机器学习软件库。
跨平台:
OpenCV 可以在不同的系统平台上使用,包括Windows,Linux,OS,X,Android和iOS。
编程语言:
OpenCV 用 C++ 语言编写,它具有 C ++,Python,Java 和MATLAB 接口,如今也提供对于 C#、Ch、Ruby,GO 的支持。
活跃的开发团队:
自从第一个预览版本于2000年公开以来,目前已更新至 OpenCV4.5.3 。
丰富的API:
完善的传统计算机视觉算法,涵盖主流的机器学习算法,同时添加了对深度学习的支持。
开源:
以 BSD 许可证授权发行,可以在商业和研究领域中 免费使用 。
增强现实 人脸识别 手势识别 人机交互 动作识别 运动跟踪 物体识别 图像分割 机器人
本文的所有操作均在通过 VMware Workstation Pro 16.2.4 软件,在 Ubuntu18.04 Desktop 系统下进行操作,安装的是 C/C++ 图像处理开源软件库 OpenCV3.4.11。
注意:若打开桌面版的Ubuntu时提醒 VMware Workstation 16 此平台不支持虚拟化的Intel VT-x/EPT. 不使用虚拟化的Intel VT-x/EPT,是否继续?
可以试试这篇 博客 里面的方法,并在设置关闭 “内核隔离”
,笔者通过此方法已经解决了该问题。
在Ubuntu中打开终端的快捷键是[Ctrl]+[Alt]+[T]
,这样我们就可以在命令行进行接下来的操作了。
sudo apt-get install cmake
sudo apt-get install build-essential libgtk2.0-dev libavcodec-dev libavformat-dev libjpeg-dev libswscale-dev libtiff5-dev
sudo apt-get install libgtk2.0-dev
sudo apt-get install pkg-config
下载地址:https://opencv.org/releases/
点击 Sources
进行下载自己需要的版本
在 windows 下载压缩包,并解压,将解压后的文件复制到 Ubuntu 系统的 home 目录下
键入[Ctrl]+[Alt]+[T]
,这样我们就可以在命令行进行接下来的操作了。
这里我的文件名为 opencv-3.4.11 ,使用 cd命令 将自己的操作路径改到 opencv-3.4.11 下
cd opencv-3.4.11
在 opencv-3.4.11 文件夹下新建 build 文件夹,并将操作路径改到build 下
mkdir build
cd build
输入如下命令,使用 cmake 编译参数::
sudo cmake -D CMAKE_BUILD_TYPE=Release -D CMAKE_INSTALL_PREFIX=/usr/local ..
这一步仍然是在 build 文件夹下进行。
sudo make -j4
可以使用
sudo make -j8
、sudo make -j4
、sudo make
注:单线程编译:sudo make
,这会等待比较长的时间,如果你想更快编译完,可以使用命令:sudo make -j4
或sudo make -j8
,而-j4
表示使用 4 个线程进行编译,而-j8
表示使用 8 个线程进行编译。
我这里使用 -j4
是因为使用 -j8
失败了,但是没有弄清楚为什么会失败
这里会等待大概十几分钟,报错的话可以多尝试几次。
sudo make install
1.用 gedit 打开 /etc/ld.so.conf
2.在文件中加上一行 include /usr/loacal/lib
其中 /usr/loacal/lib
是 OpenCV 安装路径也就是 makefile 中指定的安装路径
sudo gedit /etc/ld.so.conf
3.修改完成后点击右上角的 save
保存后会看到之前的警告信息,不用担心,这是正常情况。键入Ctrl+C
来继续下面的操作。
4.更新系统共享链接库:
sudo ldconfig
5.配置 bash ,修改 bash.bashrc 文件:
sudo gedit /etc/bash.bashrc
在文件末尾加入:
PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig
export PKG_CONFIG_PATH
6.保存并退出,然后执行如下命令使得配置生效:
source /etc/bash.bashrc
7.更新一下:
sudo updatedb
接下来查看 OpenCV 的版本信息是否匹配:
pkg-config --modversion opencv
至此,OpenCV 的安装终于完成了。
1) 编写一个打开图片进行特效显示的代码 test1.cpp;
2)解释 gcc test1.cpp -o test1 `pkg-config --cflags --libs opencv`
这条编译命令,它是如何获得opencv头文件、链接lib库文件的路径的?
3)改用make+makefile方式编译上述程序(用变量命名格式写makefile文件,并包括 clean选项)
创建一个文件夹存放代码文件:
mkdir test1
cd test1
创建一个 test1.cpp 文件。
vim test1.cpp
#include
#include
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
CvPoint center;
double scale = -3;
IplImage* image = cvLoadImage("test1.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;
}
编译分两种情况:
c++文件编译命令:
g++ test1.cpp -o test1 `pkg-config --cflags --libs opencv`
c文件编译命令:
gcc test1.cpp -o test1 `pkg-config --cflags --libs opencv`
./ test1
虽然上面的操作可以实现图片进行特效显示,但是会提醒 Failed to load module “canberra-gtk-module”
我们只需要重新安装一下 canberra-gtk-module
sudo apt-get install libcanberra-gtk-module
安装完成后,重新启动虚拟机,再执行 test1 就不会报错了
gcc test1.cpp -o test1 `pkg-config --cflags --libs opencv`
命令格式:
gcc编译器:
gcc/g++ + 文件名 + -o + 输出文件流名称 + `支持包`
命令解析:
这个编译命令中用到了 pkg-config 工具,它主要有以下几个功能:
使用 pkg-config 时,选项 - -cflags 它是用来指定程序在编译时所需要头文件所在的目录,选项 - -libs 则是指定程序在链接时所需要的动态链接库的目录。
gcc 编译命令: gcc test1.cpp -o test1 `pkg-config --cflags --libs opencv`
这条编译命令,就是通过上述方式获得 opencv 头文件、以及链接lib库文件的路径的。
pkg-config --cflags --libs opencv
vim makefile
.PHONY: clean
CC = g++
BIN = a.out
OBJS = test1.o
TCPP = test1.cpp
T = test1
OPCV = `pkg-config --cflags --libs opencv`
$(T): $(TCPP)
$(CC) $(TCPP) -o $(T) $(OPCV)
$(BIN): $(OBJS)
$(CC) -o $(BIN) $(OBJS)
$(OBJS): $(TCPP)
$(CC) -c -o $(OBJS) $(TCPP)
clean:
rm -f $(BIN) $(OBJS)
注意:每一句recipe(就是要执行的shell命令)的开头,都必须有一个tab。 而makefile中的其他东西,例如 target: prerequisite、ifeq 、变量赋值等等,前面一般不能有tab
make
make命令
,并键入 ./test1
,发现能够实现特效展示,并且在test1 文件夹下生成了 test1可执行文件和test.png。meke+makefile
实现了该程序的编译工作。(1)练习使用opencv库编写打开摄像头压缩视频的程序。参考示例代码1和示例代码2。
(2)回答:
a.如果要求打开你硬盘上一个视频文件来播放,请问示例代码1第7行代码如何修改?
b.在示例代码1第9行的while循环中,Mat是一个什么数据结构? 为什么一定要加一句waitKey延时代码,删除它行不行?
c.示例代码1代码会在while循环中一直运行,你如果试图用鼠标关闭图像显示窗口,会发现始终关不掉。需要用键盘Ctrl+C 强制中断程序,非常不友好。如何改进?
mkdir test2
cd test2
vim test2.cpp
//改进前的代码
#include
using namespace cv;
int main()
{
VideoCapture capture(0);
while(1)
{
Mat frame;
capture >> frame;
imshow("读取视频帧",frame);
waitKey(30);
}
system("pause");
return 0;
}
//改进后的代码
#include
using namespace cv;
int main()
{
//从文件中读取视频
VideoCapture capture("111.mp4");
//循环显示每一帧
while(1){
Mat frame;//定义一个Mat变量,用于存储每一帧的图像
capture >> frame;//读取当前帧
if(frame.empty())//播放完毕,退出
break;
imshow("读取视频帧",frame);//显示当前帧
waitKey(30);//掩饰30ms
}
system("pause");
return 0;
}
代码说明(解决目标中的遗留问题):
a.如果要求打开你硬盘上一个视频文件来播放,请问示例代码1第7行代码如何修改?
第七行语句:VideoCapture capture(0)
,后面的参数设置为 0 ,则从摄像头读取视频并循环显示每一帧;如果设置为一个视频的文件名,比如:111.mp4 ,则会将视频读取并循环显示每一帧。
b.在示例代码1第9行的while循环中,Mat是一个什么数据结构? 为什么一定要加一句waitKey延时代码,删除它行不行?
while 循环体中的 Mat 数据结构其实是一个点阵,对应图像上的每一个点,点的集合形成了一帧图像,有关 Mat 详解请看:OpenCV中Mat数据结构
waitKey(30)
,中的参数单位是 ms 毫秒,也就是每一帧间隔 30 ms ,该语句时不能删除的,否则会执行错误,无法播放视频或录制视频。
c.示例代码1代码会在while循环中一直运行,你如果试图用鼠标关闭图像显示窗口,会发现始终关不掉。需要用键盘Ctrl+C 强制中断程序,非常不友好。如何改进?
原代码会在while循环中一直运行,如果试图用鼠标关闭图像显示窗口,会发现始终关不掉。需要用键盘 Ctrl+C 强制中断程序,本文中的 test2.cpp 已经经过修改,当视频播放完后,会自动结束播放
g++ test2.cpp -o test2 `pkg-config --cflags --libs opencv`
./test2
运行可执行文件,发现可以播放视频 111.mp4由于本人的电脑没有摄像头,所以接下来这一部分借用同学的电脑来完成。
由于本人的电脑没有摄像头,所以接下来这一部分借用同学的电脑来完成。
mkdir test3
cd test3
vim test3.cpp
/*********************************************************************
打开电脑摄像头,空格控制视频录制,ESC退出并保存视频RecordVideo.avi
*********************************************************************/
#include
#include
#include
#include
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;
}
g++ test3.cpp -o test3 `pkg-config --cflags --libs opencv`
./test3
按 Esc 退出录制并保存 .avi 文件:
到此就成功实现了调用摄像头录制视频的目的。
通过学习opencv图像库编程,我了解如何借助第三方库函数完成一个综合程序设计,也实现了桌面版Ubuntu的初步探索,加深了我对makefile的理解。但是也让我认识到了自己对Ubuntu的理解和认识仍然停留在初级水平,还远远不能独立实现在ubuntu系统下的综合程序设计,还需要不断地学习来提升自己的水平和能力。本次实验中需要用到摄像头,但是由于我的电脑上没有摄像头,我尝试了多种方法来通过USB连接来调用手机上面的摄像头,但是在Ubuntu系统下未能实现,在Windows系统下可以通过DroidCam来实现。
参考列表:
1.OpenCV
2. OpenCV简介
3. VMware Workstation 16 在此主机上不支持嵌套虚拟化 修复方法
4. ubuntu安装opencv的正确方法
5.Ubuntu18.04下OpenCV3.4.11的安装及使用示例
6.Ubuntu18.04使用opencv库编写打开摄像头压缩视频