目录
(4)在mainwindow.cpp中编写代码在窗口加载图片
一.Qt环境准备
上一篇博客我讲了如何下载配置OpenCV库,但是在Qt5.15.2使用OpenCV库时,出现了一个问题就是我下载的Qt5.15.2是x86架构的,不能对OpenCV库进行链接,而OpenCV库是arm架构的
直接使用Qt5.15.2编译链接OpenCV库链接头文件是可以的,但是使用OpenCV代码就不能成功链接编译了
因此需要下载Qt6.3.1版本的, Qt6.3.1版本是arm架构的
下载完成后打开Qt Creator在Qt版本里面加入Qt6.3.1的qmake
一般是在下载的Qt版本文件bin目录下
再在构建配套(Kit)中加入Qt6.3.1版本的构建配套
这样Qt环境就搭建好了
二.在Qt项目中加载Opencv库并编写代码测试
1.使用Opencv加载图片
(1)在Qt中创建一个新项目
选择Qt6.3.1(arm)
(2)在.pro文件中链接OpenCV库
#链接OpenCV头文件
INCLUDEPATH +=/usr/local/include/
INCLUDEPATH +=/usr/local/include/opencv4/
INCLUDEPATH +=/usr/local/include/opencv4/opencv2
#链接OpenCV库文件
LIBS += -L/usr/local/lib -lopencv_gapi \
-lopencv_stitching -lopencv_aruco -lopencv_bgsegm -lopencv_bioinspired \
-lopencv_ccalib -lopencv_dnn_objdetect -lopencv_dnn_superres -lopencv_dpm \
-lopencv_highgui -lopencv_face -lopencv_freetype -lopencv_fuzzy -lopencv_hfs \
-lopencv_img_hash -lopencv_line_descriptor -lopencv_quality -lopencv_reg \
-lopencv_rgbd -lopencv_saliency -lopencv_sfm -lopencv_stereo -lopencv_structured_light \
-lopencv_phase_unwrapping -lopencv_superres -lopencv_optflow -lopencv_surface_matching \
-lopencv_tracking -lopencv_datasets -lopencv_text -lopencv_dnn -lopencv_plot \
-lopencv_videostab -lopencv_videoio -lopencv_xfeatures2d -lopencv_shape -lopencv_ml \
-lopencv_ximgproc -lopencv_video -lopencv_xobjdetect -lopencv_objdetect \
-lopencv_calib3d -lopencv_imgcodecs -lopencv_features2d -lopencv_flann -lopencv_xphoto \
-lopencv_photo -lopencv_imgproc -lopencv_core
(3)添加新资源文件
(4)在mainwindow.cpp中编写代码在窗口加载图片
#include "ui_mainwindow.h"
#include <opencv2/opencv.hpp>
#include <QDebug>
#include <QFile>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
//以只读的方式打开图片文件
QFile file(":/img/tree.jpg");
if(!file.open(QFile::ReadOnly)) {
qDebug() << "打开图片失败";
}
//将整个图片文件内容读取到一个 QByteArray 对象中
QByteArray photo = file.readAll();
cv::Mat img = cv::imdecode(std::vector<char>(photo.begin(), photo.end()), cv::IMREAD_COLOR);
//判定图片是否加载成功
if(img.empty()){
qDebug() << "没有找到照片";
}
cv::namedWindow("tree", cv::WINDOW_AUTOSIZE);
cv::imshow("tree", img);
cv::waitKey(0); //cv::waitKey(10000);
cv::destroyWindow("tree");
}
MainWindow::~MainWindow()
{
delete ui;
}
运行结果:
(5)代码中使用的OpenCV函数分析
1)cv::imdecode()函数
//cv::Mat是OpenCV用于处理所有图像类型的结构
//cv::imdecode() 函数将 QByteArray 转换为 OpenCV 的图像格式 cv::Mat,以便进一步处理,cv::IMREAD_COLOR表示以彩色模式加载图像
cv::Mat img = cv::imdecode(std::vector<char>(photo.begin(), photo.end()), cv::IMREAD_COLOR);
函数原型:
Mat cv::imdecode (InputArray buf, int flags);
Mat cv::imdecode (InputArray buf, int flags, Mat *dst);
函数功能:
从内存的缓存区中读取图片
参数: buf:一个数组或字节数组
flags:用来指定图像加载的标志,通过这个参数,可以控制图像加载的一些行为和选项
下面是falgs的枚举类型:
enum cv::ImreadModes {
cv::IMREAD_UNCHANGED = -1, //按图像原样加载图像
cv::IMREAD_GRAYSCALE = 0, //以灰度模式加载图像
cv::IMREAD_COLOR = 1, //以彩色模式加载图像
cv::IMREAD_ANYDEPTH = 2, //以原始深度加载图像
cv::IMREAD_ANYCOLOR = 4, //以任意颜色模式加载图像,返回一个3通道图像
cv::IMREAD_LOAD_GDAL = 8, //使用gdal驱动程序加载图像
cv::IMREAD_REDUCED_GRAYSCALE_2 = 16, //将图像转换为单通道灰度图像,图像尺寸减小1/2
cv::IMREAD_REDUCED_COLOR_2 = 17, //图像转换为3通道BGR彩色图像,图像大小减少1/2
cv::IMREAD_REDUCED_GRAYSCALE_4 = 32, //将图像转换为单通道灰度图像,图像尺寸减小1/4
cv::IMREAD_REDUCED_COLOR_4 = 33, //将图像转换为3通道BGR彩色图像,图像大小减少1/4
cv::IMREAD_REDUCED_GRAYSCALE_8 = 64, //将图像转换为单通道灰度图像,图像尺寸减小1/8
cv::IMREAD_REDUCED_COLOR_8 = 65, //将图像转换为3通道BGR彩色图像,图像大小减少1/8
cv::IMREAD_IGNORE_ORIENTATION = 128 //不根据EXIF的方向标志旋转图像(EXIF(Exchangeable Image File Format)是一种图像文件格式,用于存储数字图像中的元数据信息,例如相机设置、拍摄日期和时间、地理位置等。)
}
dst(可选):用于接收解码后的图像数据
返回值:
成功: 一个Mat类型的值
失败: NULL
例子:
cv::Mat image; // 定义用于存储解码后图像的 cv::Mat 对象 cv::imdecode(buffer, flags, &image);
通过传递
&image
给cv::imdecode()
函数的dst
参数,解码后的图像数据将直接存储在image
中也可以不使用第三个参数,直接使用返回值
cv::Mat image; // 定义用于存储解码后图像的 cv::Mat 对象 image = cv::imdecode(buffer, flags);
2)cv::namedWindow()函数
//cv::namedWindow():函数将会在屏幕上打开一个窗口,窗口名为tree,cv::WINDOW_AUTOSIZE是窗口的属性:窗口的大小与载入的图片大小一致,图片会被缩放大小来适应窗口大小
cv::namedWindow("tree", cv::WINDOW_AUTOSIZE);
函数原型:
void cv::namedWindow(const String &winname,int flags = WINDOW_AUTOSIZE);
函数功能:
函数namedWindow创建一个窗口,该窗口可用作图像和跟踪条的占位符。创建的窗口通过窗口名称来引用
参数:
winname: 窗口标题,也是用于窗口标识符的窗口名称
flags: 窗口标志
下面是falgs的枚举类型:
enum cv::WindowFlags {
cv::WINDOW_NORMAL = 0x00000000, //用户可以调整窗口的大小(没有限制)/也可以将全屏窗口切换到正常大小
cv::WINDOW_AUTOSIZE = 0x00000001, //用户无法调整窗口大小,窗口大小受显示图像的限制
cv::WINDOW_OPENGL = 0x00001000, //支持opengl的窗口
cv::WINDOW_FULLSCREEN = 1, //将窗口改为全屏
cv::WINDOW_FREERATIO = 0x00000100, //图像尽可能地扩展(没有比例限制)
cv::WINDOW_KEEPRATIO = 0x00000000, //保持图像原有的比例
cv::WINDOW_GUI_EXPANDED =0x00000000, //状态栏和工具栏
cv::WINDOW_GUI_NORMAL = 0x00000010 //默认的窗口模式,会在图像显示时以普通窗口的形式呈现,并提供基本的窗口操作,如调整大小、移动和关闭
}
返回值:
无返回值
3)cv::imshow()函数
//cv::imshow():函数将会创建一个窗口(如果这个窗口不存在,会自动调用cv::namedWindow()函数来新建一个窗口),调用cv::imshow()会将指定的图片绘制在窗口上
cv::imshow("tree", img);
函数原型:
void cv::imshow(const String &winname, InputArray mat);
函数功能:
在指定窗口中显示图像
参数:
winname: 指定的窗口对象
mat: 展示的图像
返回值:
无返回值
4)cv::waitKey()函数
//cv::waitKey():系统暂停并等待键盘事件发生(如果传入的参数值大于零,就会等待该值的毫秒时间(如果在等待时间中有键盘事件发生,会立马继续执行后面的程序),然后继续执行后面程序,如果参数设置为0或负数,程序将会无限等待,直到有键盘事件发生)
cv::waitKey(0); //cv::waitKey(10000);
函数原型:
int cv::waitKey (int delay = 0);
函数功能:
等待键盘事件发生
参数:
delay: 以毫秒为单位的延迟。0是代表“永远”的特殊值
返回值:
返回按下的键的代码,如果在指定时间之前没有按下键,则返回-1
5)cv::destroyWindow()函数
//cv::destroyWindow() 关闭指定的窗口并释放相关内存空间
cv::destroyWindow("tree");
函数原型:
void cv::destroyWindow(const String &winname);
函数功能:
销毁指定的窗口
参数:
winname: 要销毁的窗口名称
返回值:
无返回值
2.使用Opencv加载视频
(1)使用Qt创建一个新项目
(2)在.pro文件中链接OpenCV库
#链接OpenCV头文件
INCLUDEPATH +=/usr/local/include/
INCLUDEPATH +=/usr/local/include/opencv4/
INCLUDEPATH +=/usr/local/include/opencv4/opencv2
#链接OpenCV库文件
LIBS += -L/usr/local/lib -lopencv_gapi \
-lopencv_stitching -lopencv_aruco -lopencv_bgsegm -lopencv_bioinspired \
-lopencv_ccalib -lopencv_dnn_objdetect -lopencv_dnn_superres -lopencv_dpm \
-lopencv_highgui -lopencv_face -lopencv_freetype -lopencv_fuzzy -lopencv_hfs \
-lopencv_img_hash -lopencv_line_descriptor -lopencv_quality -lopencv_reg \
-lopencv_rgbd -lopencv_saliency -lopencv_sfm -lopencv_stereo -lopencv_structured_light \
-lopencv_phase_unwrapping -lopencv_superres -lopencv_optflow -lopencv_surface_matching \
-lopencv_tracking -lopencv_datasets -lopencv_text -lopencv_dnn -lopencv_plot \
-lopencv_videostab -lopencv_videoio -lopencv_xfeatures2d -lopencv_shape -lopencv_ml \
-lopencv_ximgproc -lopencv_video -lopencv_xobjdetect -lopencv_objdetect \
-lopencv_calib3d -lopencv_imgcodecs -lopencv_features2d -lopencv_flann -lopencv_xphoto \
-lopencv_photo -lopencv_imgproc -lopencv_core
(3)在mainwindow.cpp中编写代码
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <QDebug>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
//新建一个窗口,窗口名为scenery,窗口模式为cv::WINDOW_AUTOSIZE
cv::namedWindow("scenery", cv::WINDOW_AUTOSIZE);
cv::VideoCapture cap; //cv::VideoCapture类型用于打开视频文件
//打开指定的视频文件
if(!cap.open("/Users/liwanyu/Downloads/opencvDemo/day1/video/videoload/video/scenery.mp4")){
qDebug() << "打开视频文件失败";
}
//打开网络视频
//cap.open("https://vd2.bdstatic.com/mda-njqbvdg1h8kdqez1/720p/h264/1666686182583726512/mda-njqbvdg1h8kdqez1.mp4?v_from_s=hkapp-haokan-hna&auth_key=1703093507-0-0-fc2c4688c205be7eedb5e09162e45f57&bcevod_channel=searchbox_feed&pd=1&cr=2&cd=0&pt=3&logid=1907408427&vid=14746953470406117750&klogid=1907408427&abtest=");
cv::Mat frame; //用于保存视频帧
//在while循环中循环播放视频
while(1){
//视频文件按照帧从视频流中读出来,每33毫秒换帧,如果在这33毫秒中有键盘事件发生就退出视频帧播放
cap.read(frame); //cap >> frame
if(frame.empty()){
break;
}
cv::imshow("scenery", frame);
if(cv::waitKey(33)>=0){
break;
}
}
cv::destroyWindow("scenery"); //关闭指定的窗口并销毁其内存空间
}
MainWindow::~MainWindow()
{
delete ui;
}
运行结果:
(4)代码中使用的OpenCV函数分析
1)cv::VideoCapture
cv::VideoCapture
功能:用于从视频文件、图像序列或相机中捕获视频的类
Public Member Functions:
默认的空构造:
cv::VideoCapture::VideoCapture();
重载的构造:
cv::VideoCapture::VideoCapture(const String &filename, int apiPreference = CAP_ANY);
功能:
打开视频文件或捕获摄像头设备或IP视频流(网络传输视频流),默认使用API首选项(CAP_ANY)进行视频捕获
参数:
filename:要打开的视频文件名、捕获设备的索引号(一般为0表示默认摄像头),或者是 IP 视频流地址
apiPreference:可选参数,用于指定视频捕获 API 的首选项。默认值为
CAP_ANY
,表示尝试使用任何可用的视频捕获 API 来打开
cv::VideoCapture::VideoCapture(const String &filename, int apiPreference, const std::vector<int> ¶ms);
功能:
打开视频文件或捕获摄像头设备或IP视频流(网络传输视频流),默认使用API首选项(CAP_ANY)进行视频捕获
参数:
filename:要打开的视频文件名、捕获设备的索引号(一般为0表示默认摄像头),或者是 IP 视频流地址
apiPreference:可选参数,用于指定视频捕获 API 的首选项。默认值为
CAP_ANY
,表示尝试使用任何可用的视频捕获 API 来打开params:可选不定参数,以向底层视频捕获库传递附加的特定参数
例如:
cv::VideoCapture cap("video.mp4", cv::CAP_FFMPEG, {cv::CAP_PROP_FRAME_WIDTH, 640, cv::CAP_PROP_FRAME_HEIGHT, 480});
在此示例中,传递了一组参数来设置所捕获视频帧的宽度和高度。使用了
cv::CAP_PROP_FRAME_WIDTH
和cv::CAP_PROP_FRAME_HEIGHT
,这些常量表示帧的宽度和高度属性,然后将期望的值分别设置为 640 和 480。这意味着设置了捕获的每个视频帧的宽度为 640 像素,高度为 480 像素。
cv::VideoCapture::VideoCapture(int index, int apiPreference = CAP_ANY);
功能:
打开摄像机进行视频捕获
参数:
index:捕获设备的索引号,用于指定要打开的特定设备。通常情况下,0 表示默认摄像头,1 表示第二个摄像头,以此类推。如果你的系统上有多个摄像头或其他捕获设备,可以通过指定不同的索引号来选择打开哪个设备
apiPreference:可选参数,用于指定视频捕获 API 的首选项。默认值为
CAP_ANY
,表示尝试使用任何可用的视频捕获 API 来打开
cv::VideoCapture::VideoCapture(int index, int apiPreference = CAP_ANY, int apiPreference, const std::vector<int> ¶ms);
功能:
使用API首选项和不定参数打开摄像机进行视频捕获。
参数:
index:捕获设备的索引号,用于指定要打开的特定设备。通常情况下,0 表示默认摄像头,1 表示第二个摄像头,以此类推。如果你的系统上有多个摄像头或其他捕获设备,可以通过指定不同的索引号来选择打开哪个设备
apiPreference:可选参数,用于指定视频捕获 API 的首选项。默认值为
CAP_ANY
,表示尝试使用任何可用的视频捕获 API 来打开params:可选不定参数,以向底层视频捕获库传递附加的特定参数
默认的析构函数:
virtual cv::VideoCapture::~VideoCapture();
其他成员函数:
virtual double cv::VideoCapture::get(int propld) const;
功能:
返回指定的VideoCapture属性
参数:
propld:要获取属性的标识符(例如,如果
propId为
CV_CAP_PROP_FRAME_WIDTH
,则该函数将返回输入视频流的帧宽度)返回值:
返回值类型为
double
,表示所请求属性的当前值
String cv::VideoCapture::getBackendName()const;
功能:
用于返回使用的视频捕获后端API的名称
参数:
无参数
返回值:
成功:String类型的后端API名称
失败:NULL
bool cv::VideoCapture::getExceptionMode();
功能:
用于获取异常模式的状态
参数:
无参数
返回值:
返回
true
,则表示异常模式已启用,即当发生错误时,将抛出异常返回
false
,则表示异常模式已禁用,即当发生错误时,不会抛出异常,而是通过错误码或其他方式通知用户
virtual bool cv::VideoCapture::grab();
功能:
用于从输入视频流中抓取一帧图像,但不将其解码
参数:
无参数
返回值:
返回
true
,则表示成功抓取了一帧图像返回
false
,则表示未能成功抓取图像
virtual bool cv::VideoCapture::isOpened()const;
功能:
用于检查当前视频捕获对象是否成功打开了视频文件或设备
参数:
无参数
返回值:
返回
true
,则表示视频捕获对象已成功打开,并且可以从该对象读取视频帧返回
false
,则表示视频捕获对象无法打开,可能是由于文件路径错误、设备未连接或者不支持的格式等原因
用于打开视频文件或设备的open函数:(open函数的参数和cv::VideoCapture:构造函数的参数一样就不再解释了)
virtual bool cv::VideoCapture::open(const String &filename, int apiPreference = CAP_ANY); virtual bool cv::VideoCapture::open(const String &filename, int apiPreference, const std::vector<int> ¶ms); virtual bool cv::VideoCapture::open(int index, int apiPreference = CAP_ANY); virtual bool cv::VideoCapture::open(int index, int apiPreference = CAP_ANY, int apiPreference, const std::vector<int> ¶ms);
重载的运算符函数:
virtual VideoCapture &operator>>(Mat &image);
功能:
用于从视频流中读取一帧图像并将其存储到提供的
Mat
对象中参数:
image
:要存储读取帧的Mat
对象。它将存储从视频流中读取的图像数据
virtual VideoCapture &operator>>(UMat &image);
功能:
用于从视频流中读取一帧图像并将其存储到提供的
UMat
对象中参数:
image
:要存储读取帧的UMat
对象。它将存储从视频流中读取的图像数据
virtual bool cv::VideoCapture::read(OutputArray image);
功能:
用于从视频流中读取一帧图像并将其存储在提供的
OutputArray
对象中参数:
image
:要存储读取帧的OutputArray
对象。它可以是Mat
、UMat
或其他可接受输出图像数据的对象类型返回值:
返回
true
,则表示成功读取到一帧图像,并将其存储在提供的OutputArray
对象中
返回false
,则表示未能成功读取图像,可能是由于视频结束、读取错误或其他原因
virtual void cv::VideoCapture::release();
功能:
用于释放视频捕获对象所占用的资源
参数:
无参数
返回值:
无返回值
virtual bool cv::VideoCapture::retrieve(OutputArray image, int flag=0);
功能:
用于解码和获取当前抓取的视频帧
参数:
image:要存储解码后图像的
OutputArray
对象。它可以是Mat
、UMat
或其他可接受输出图像数据的对象类型falg:可选参数,用于指定附加的操作标志。默认值为0
返回值:
返回
true
,则表示成功解码当前抓取的视频帧,并将其存储在提供的OutputArray
对象中返回
false
,则表示未能成功解码视频帧
virtual bool cv::VideoCapture::set(int propId, double value);
功能:
用于设置视频捕获对象的属性值
参数:
propId
:要设置的属性的标识符。可以使用不同的标识符来设置不同的属性值。例如,如果propId
为CV_CAP_PROP_FRAME_WIDTH
,则代表设置输入视频流的帧宽度
value
:要设置的属性值返回值:
返回
true
,则表示成功设置属性的值返回
false
,则表示无法设置属性的值,可能是由于不支持的属性或其他原因
void cv::VideoCapture::setExceptionMode(bool enable);
功能:
用于设置异常模式的状态
参数:
enable:一个
bool
值,表示是否启用异常模式。如果enable
为true
,则启用异常模式,即当发生错误时,将抛出异常 ;如果enable
为false
,则禁用异常模式,即当发生错误时,不会抛出异常,而是通过错误码或其他方式通知用户返回值:
无返回值
静态成员函数:
static bool cv::VideoCapture::waitAny(const std::vector< VideoCapture > &streams, std::vector< int > &readyIndex, int64 timeoutNs=0);
功能:
静态成员函数,用于等待多个视频捕获对象中至少一个准备就绪(有可读取的帧)
参数:
streams
:一个包含多个VideoCapture
对象的std::vector
,表示要等待的视频捕获对象列表。
readyIndex
:一个空的std::vector<int>
,用于存储准备就绪的视频捕获对象的索引。准备就绪的对象即有可读取的帧。
timeoutNs
:可选参数,以纳秒为单位指定的超时时间。默认值为0,表示无限等待返回值:
返回
true
,则表示至少一个视频捕获对象已准备就绪。返回
false
,则表示在超时时间内没有可用的视频捕获对象
友元类:
friend class internal::VideoCapturePrivateAccessor