本文目的是通过在Ubuntu18.04系统上编译安装著名的C/C++图像处理开源软件库OpenCV3.4.12,同时练习使用OpenCV对图片和视频进行处理。
目录
(一)编译安装OpenCV
1.编译安装源代码
参考博客:ubuntu安装opencv的正确方法
2.遇到的问题
- 按照该博客使用命令
sudo make -j8
进行多线程编译时,刚开始时编译正常,后来编译到70%左右时开始报错。
报错如下:
- 解决方法
参考文章:很感谢这篇文张【已解决】Makefile:xxx: recipe for target xxx failed +【顺带搞懂了】如何忽略makefile执行过程中的某些命令的错误而得以继续运行受到这篇文章的启发,我感觉可能是因为多线程编译时导致编译生成的链接文件没有及时生成,而其它线程编译时又需要该文件,因此导致了这种错误的产生。在使用单线程编译后就可以正常编译成功。
3.验证安装成功
使用命令pkg-config opencv --modversion
检验安装是否成功,若安装成功则显示OpenCV的版本号。
(二)使用OpenCV对图片进行处理
1.编写程序
- test.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("star.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;
src=cvarrToMat(image);
imwrite("test.png",src);
imshow("test",src);
cvWaitKey();
return 0;
}
2.编译运行程序
- 编译程序
使用命令gcc test.cpp -o test `pkg-config --cflags --libs opencv`
进行编译时报错,报错如下:
- 解决方法:使用命令
g++ test.cpp -o test `pkg-config --cflags --libs opencv`
(注意:````pkg-config --cflags --libs opencv` ```中的的引号为反引号)
这个错误可能是因为gcc编译器不能编译C++程序导致的。
- 解决方法:使用命令
- 编译过程中g++如何获取opencv头文件、链接lib库文件的路径
- 通过命令
pkg-config --cflags --libs opencv
获取
反引号表示输出字符串,所以使用g++ test.cpp -o test `pkg-config --cflags --libs opencv`
编译程序时首先会将pkg-config --cflags --libs opencv
替换为如下的OpenCV头文件和库文件的路径,从而获取OpenCV头文件、链接lib库文件的路径。
- 通过命令
- 然后g++编译器再到该OpenCV头文件和库文件的路径找到需要的依赖进行程序的编译,最后编译成功。
- 运行程序
使用命令./test
执行该程序,发现程序正常执行但是会产生警告,警告如下:
- 成功运行
(三)使用OpenCV对视频进行处理
1.源程序
- video.cpp(使用电脑摄像头读取视频并显示)
#include<opencv2/opencv.hpp>
using namespace cv;
int main()
{
char key;
VideoCapture capture(0); //从摄像头读取视频
// VideoCapture capture("你的名字.mp4"); //从本地磁盘读取视频
while(1) //循环显示每一帧形成视频
{
Mat frame; //定义Mat变量储存每一帧图像
capture>>frame; //读取当前帧
imshow("读取视频",frame); //显示当前帧
waitKey(30); //延时
}
return 0;
}
- video_record.cpp(使用电脑摄像头录制视频)
/*********************************************************************
@名字:video_record
@功能:使用电脑摄像头录制视频
@按键:空格视频录制,ESC 退出并保存视频 RecordVideo.avi
*********************************************************************/
#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 capture(0); //打开电脑摄像头
if (!capture.isOpened())
{
cout << "error" << endl;
waitKey(0);
return -1;
}
int w = static_cast<int>(capture.get(CV_CAP_PROP_FRAME_WIDTH)); //获得capture的分辨率
int h = static_cast<int>(capture.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)
{
capture >> frame;
key = waitKey(100);
if (key == 32) //按下空格开始录制、暂停录制
{
startOrStop =1-startOrStop;
if (startOrStop == 0) flag = 1; //可以来回切换
}
if (key == 27) break; //按下 ESC 退出整个程序,保存视频文件到磁盘
if (startOrStop == 0 && flag==1)
{
writer << frame;
cout << "recording" << endl;
}
else if (startOrStop == 1 && flag==1)
{
flag = 0;
cout << "pause recording" << endl;
}
imshow("picture", frame);
}
capture.release();
writer.release();
destroyAllWindows();
}
2.虚拟机连接摄像头
- 参考文章:ubuntu 虚拟机下使用摄像头
+遇到的问题- 按照该博客进行虚拟机连接摄像头后,使用命令
cheese
打开摄像头报错说 未发现设备。
- 解决方法:
由于我这里有Webcam_HD,也就是windows系统上设备管理器中的照相机的设备,所以我就直接连接它到虚拟机中,这样就可以在虚拟机中正常使用照相机了。
再次执行命令cheese
就可以开启摄像头。
- 按照该博客进行虚拟机连接摄像头后,使用命令
3.使用OpenCV打开摄像头
- 使用命令
g++ video.cpp -o video `pkg-config --cflags --libs opencv`
编译生成video可执行文件,输入命令./video
打开摄像头
- 对程序的思考
- 如果想打开硬盘上的视频文件来播放,则应该使用
VideoCapture capture("你的名字.mp4");
(其中你的名字.mp4为文件名) - 在video.cpp中的while循环中,Mat是一个什么数据结构? 为什么一定要加一句waitKey延时代码,删除它行不行?
Mat是一个类,由两个数据部分组成:矩阵头(包含矩阵尺寸、存储方法、存储地址等信息)和一个指向存储所有像素值的矩阵(根据所选存储方法的不同,矩阵可以是不同的维数)的指针。
加入waitKey延时,这样便于刷新储存每一帧图像,不会造成视频卡顿之类的问题。如果不加入延时的话会导致视频显示窗口无法显示。 - video代码会在while循环中一直运行,你如果试图用鼠标关闭图像显示窗口,会发现始终无法关掉。需要用键盘输入
Ctrl+C
强制中断程序,非常不友好。如何改进?
可以在while循环里加入按键退出的代码如下(按q键退出):
key = waitKey(1) & 0xff; //按q键退出 if(key == 'q') break;
- 如果想打开硬盘上的视频文件来播放,则应该使用
- 摄像头拓展使用:录制视频
使用命令g++ video_record.cpp -o video_record `pkg-config --cflags --libs opencv`
编译程序,然后运行进行录制视频操作,最后退出程序时将录制的视频保存到程序所在目录。
(四)实验总结
通过在Ubuntu系统上安装编译OpenCV3.4.12,并且调用OpenCV的接口函数进行图片以及视频的处理,让我对于使用OpenCV进行图像编程有了更加深入的了解,同时也体验到了OpenCV开源库在图像编程方面的强大之处。在编译安装、程序运行的过程中,我也遇到了许多的问题,但是在自己不断的查阅资料以及各种方式的尝试中终于还是解决了遇到的问题,而在解决这些问题的同时也在不断提升自己解决问题的能力。
感谢以下博文对我的帮助和启发:
(1)https://blog.csdn.net/public669/article/details/99044895
(3)https://www.jianshu.com/p/e1d3f98e3d04
(4)https://blog.csdn.net/oXiaoXue123456789/article/details/107115584/