QT开发笔记(Camera)
Camera
此章节例程适用于 Ubuntu 和正点原子 I.MX6U 开发板,不适用于 Windows(需要自行修改
才能适用 Windows,Windows 上的应用不在我们讨论范围)!
资源简介
正点原子 I.MX6U 开发板底板上有一路“CSI”摄像头接口。支持正点原子的 OV5640、
OV2640 和 OV7725(不带 FIFO)。同时有 USB 接口,可以接 USB 免驱摄像头。例程兼容 USB
摄像头与正点原子的 OV5640、OV2640 和 OV7725 摄像头。
出厂系统请更新到正点原子 I.MX6U 最新的出厂系统,在驱动层正点原子对 OV5640、
OV2640 和 OV7725 摄像头维护、优化或者添加支持。
环境搭建
Qt 里也有一个 QCamera 类。没错,确实可以使用这个 QCamera 类来开发摄像头。但是这
个类在正点原子的 I.MX6U 开发板 4.1.15 内核版本上不能使用 OV5640、OV2640 和 OV7725,
可以使用 USB 免驱摄像头。因为 OV5640、OV2640 和 OV7725 的驱动默认是读取 YUYV 格式
数据,而 QCamera 里读取的数据是 RGB 格式数据,它们可能数据对不上就无法使用了!但是
也不建议修改驱动的方法来使用 QCamera,防止 QCamera 在某些方法上与驱动层不对应,导致
使用报错。
实际上我们使用 V4l2 编程就可以对摄像头进行编程,效果会比在 Qt 显示流畅,因为 V4l2
的数据直接可以显示在 fb0(也就是屏上)。而经过 Qt 还需要在控件上处理,所以效率会慢一些!
在正点原子 I.MX6U 开发板上或者说是嵌入式上,比较低性能的 CPU 对于处理图像等大数据还
是比较吃力的。所以我们需要去优化,不同的编程方式,对数据的处理不同,写出来的效果也
会不同!
下面主要介绍 Qt + OpenCV 调用摄像头,效果肯定不能与使用 V4l2 直接显示在 fb0 上相比。
在这个开发板的 CPU 上显示效果还是比较好的,还能接受,流畅度一般。这个可能是 OpenCV
在对摄像头数据做了一定的处理才会变的慢了。
要想在 Ubuntu 上使用 OpenCV,那么我们的 Ubuntu 上必须有 OpenCV 的库,如果您不想
在 Ubuntu 安装 OpenCV,就可以跳过这小节,直接用出厂系统提供的交叉编译工具链,里面已
经提供有 OpenCV。在 Ubuntu 上安装 OpenCV 只是方便我们测试界面,编写的程序也可以在
Ubuntu 上运行。安装的步骤也比较简单。
正点原子 I.MX6U 出厂系统的 OpenCV 版本为 3.1.0。也不一定非要与正点原子 I.MX6U 出
厂系统里的 OpenCV 相同版本,我们只是在 Ubuntu 上运行 OpenCV。其中用到的 API 在 3.1.0
版本与 3.4.1 版本基本没有什么区别。3.1.0 版本的 OpenCV 与 3.4.1 版本的 OpenCV 绝大多数核
心 API 都相同,不必要担心找不到相同的 API。
这里笔者选择安装到 OpenCV 版本为 3.4.1 版本,因为 3.1.0 版本在配置 cmake 时下载的第
三方库因为网络的原因难下载,导致 cmake 配置不过去。(PS:如果不是因为编译不过去,笔者
会选择与开发板相同的版本的 OpenCV 的)。
进入 OpenCV 的官网 https://opencv.org/releases。下载 3.4.1 版本的 OpenCV,如下图。我们
选择 Sources(源码)进行下载。
右键选择复制下载链接,用迅雷下载会比较快。下载完成后我们拷贝下载的文件到 Ubuntu
上进行解压。或者直接在正点原子的 I.MX6U 的光盘资料路径下找到开发板光盘 A-基础资料/1、
例程源码/7、第三方库源码/opencv-3.4.1.tar.gz。然后拷贝到 Ubuntu 下。
如下图我们已经下载好文件,并拷贝下载好的文件到 Ubuntu 的家目录下。
执行下面的指令进行解压。解压将会得到一个 opencv-3.4.1 文件夹,我们使用 cd 指令进入
此文件夹。
tar xf opencv-3.4.1.tar.gz
cd opencv-3.4.1
安装 cmake,用于生成编译 OpenCV 所需要的文件。
sudo apt-get install cmake
新建一个 build 目录,并进入,用于编译生成的文件。
mkdir build
cd build
执行 cmake 配置编译。注意下面的指令“…”不要漏了!这里表示上一层目录。cmake 会从
上一层目录下找配置项,并配置到当前目录。
cmake …
在配置的过程中 cmake 会下载一些库,如 ippicv_2017u3_lnx_intel64_general_20170822.tgz,
需要一段时间,请等待,如果不能下载成功请重复尝试。
cmake 配置成功如下图。
执行 make 开始编译。输入下面的指令。
make -j 16 // 以实际分配给虚拟机的核心数为准,最佳为分配给虚拟
机核心数据的 2 倍。笔者的虚拟机最大分配了 16 个核心,笔者个人的电脑并不快,就是核心多,
所以编译就快。编译完成耗时约 5 分钟。不要只输入 make,否则将编译很久!需要加参数 -j n,
n 请根据个人虚拟机的实际情况。
执行下面的指令安装,安装到系统目录,需要加 sudo 权限。
sudo make install
安装完成如下。可以看到库被安装到/usr/local/lib 下,头文件被安装在/usr/local/include 下。
我们只需要知道安装的库路径和头文件路径即可在 Qt 里调用 Ubuntu 安装的 OpenCV。头
文件作用来编写程序,库路径用来运行程序时调用。我们只要在 Qt 的 pro 项目文件里指定这两
个路径即可。
应用实例
请根据【正点原子】I.MX6U 出厂系统 Qt 交叉编译环境搭建 V1.x.pdf(x >= 6)的文档搭建好
I.MX6U 的交叉编译环境。交叉编译工具链里已经有 OpenCV,所以我们只要在我们搭建的交叉
环境下就可以调用 OpenCV 的相关 API 进行编写 Qt 项目了。
项目简介:Qt 加 OpenCV 打开摄像头采集图像并拍照。
例 05_opencv_camera,Qt Camera 编程(难度:较难)。项目路径为 Qt/3/05_opencv_camera。
用脚本打开 Qt Creator,必须按出厂系统 Qt 交叉编译环境搭建 V1.x.pdf(x >= 6)的文档搭建
好交叉编译环境,用脚本启动时,脚本有相应的环境变量,编译时会用到。
/opt/Qt5.12.9/Tools/QtCreator/bin/qtcreator.sh &
编写程序应使用我们搭建的 ATK-I.MX6U 套件编写,否则若选择了 Desktop Qt 5.12.9 GCC
64bit,如果我们的 Ubuntu 没有安装 OpenCV 就会使用不了 OpenCV。如果您在 19.2 小节已经
安装过 OpenCV,那么下面两个套件都可一起选。本次笔者两个一起选,因为笔者有 USB 摄像
头可以在 Ubutnu 上使用 OpenCV 测试,编写的程序交叉编译后在 I.MX6U 开发板使用 USB 免
驱摄像头或者正点原子 OV5640/OV7725(不带 FIFO 款)/OV2640 测试成功!
下面开始编写程序。首先我们需要在项目 pro 文件添加 OpenCV 库的支持及头文件路径。
05_opencv_camera.pro 文件如下,添加以下内容,这里主要是判断交叉编译器的类型,然
后链接到不同的头文件路径与库。
1 QT += core gui 2 3 greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 4 5 CONFIG += c++11 6 7 # The following define makes your compiler emit warnings if you use 8 # any Qt feature that has been marked deprecated (the exact warnings 9 # depend on your compiler). Please consult the documentation of the 10 # deprecated API in order to know how to port your code away from it. 11 DEFINES += QT_DEPRECATED_WARNINGS 12 13 # You can also make your code fail to compile if it uses deprecated APIs. 14 # In order to do so, uncomment the following line. 15 # You can also select to disable deprecated APIs only up to a certain
version of Qt. 16 #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the
APIs deprecated before Qt 6.0.0 17 18 TARGET_ARCH = $${QT_ARCH} 19 contains(TARGET_ARCH, arm){ 20 CONFIG += link_pkgconfig 21 PKGCONFIG += opencv 22 INCLUDEPATH +=
/opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/cortexa7hf-neon-poky-linux-gnuea
bi/usr/include 23 } else { 24 LIBS += -L/usr/local/lib \ 25 -lopencv_core \ 26 -lopencv_highgui \ 27 -lopencv_imgproc \ 28 -lopencv_videoio \ 29 -lopencv_imgcodecs 30 31 #INCLUDEPATH 可写可不写,系统会到找到此路径 32 INCLUDEPATH += /usr/local/include 33 } 34 35 SOURCES += \ 36 camera.cpp \ 37 main.cpp \ 38 mainwindow.cpp 39 40 HEADERS += \ 41 camera.h \ 42 mainwindow.h 43 44 # Default rules for deployment. 45 qnx: target.path = /tmp/$${TARGET}/bin 46 else: unix:!android: target.path = /opt/$${TARGET}/bin 47 !isEmpty(target.path): INSTALLS += target
第 18 行,获取编译器的类型。
第 19 行,判断交叉编译器的类型是否为 arm。
第 22 行,arm 对应 opencv 的头文件路径,可以不写,编译不会报错,但是我们想查看对
应的头文件,就不得不包括这个路径了,否则跳转不过去!
第 24~32 行,添加库的支持。-L 后面指的是库文件路径,-l 后面的是相关库参数(l 是大
字母“L”的小写字母“l”,不是一),如果不会写库的名称,可以参考 Ubuntu 的 OpenCV 安装
路径下的/usr/local/lib/pkgconfig/opencv.pc 文件。
camera.h 文件,此文件声明了一个 Camera 类,其内容如下,比较简单。
9 #ifndef CAMERA_H 10 #define CAMERA_H 11 12 #include <QImage> 13 #include <QTimer> 14 /* 使用命名空间 cv 下的 VideoCapture 与 Mat 类 */ 15 namespace cv { 16 class VideoCapture; 17 class Mat; 18 } 19 20 class Camera : public QObject 21 { 22 Q_OBJECT 23 public: 24 explicit Camera(QObject *parent = nullptr); 25 ~Camera(); 26 27 signals: 28 /* 声明信号,用于传递有图片信号时显示图像 */ 29 void readyImage(const QImage&); 30 31 public slots: 32 /* 用于开启定时器 */ 33 bool cameraProcess(bool); 34 35 /* 选择摄像头 */ 36 void selectCameraDevice(int); 37 38 private slots: 39 /* 定时器时间到处理函数,发送图像数据信号 */ 40 void timerTimeOut(); 41 42 private: 43 /* 声明 OpenCV 的 cv 命名空间下的 VideoCapture 对象 */ 44 cv::VideoCapture * capture; 45 46 /* 定时器 */ 47 QTimer * timer; 48 49 /* 图像转换处理函数 */ 50 QImage matToQImage(const cv::Mat&); 51 }; 52 53 #endif // CAMERA_H 54
camera.cpp 类的定义如下。
9 #include "camera.h"10 #include "opencv2/core/core.hpp" 11 #include "opencv2/highgui/highgui.hpp" 12 #include <QImage> 13 #include <QDebug> 14 15 Camera::Camera(QObject *parent) : 16 QObject(parent) 17 { 18 /* 实例化 */ 19 capture = new cv::VideoCapture(); 20 timer = new QTimer(this); 21 22 /* 信号槽连接 */ 23 connect(timer, SIGNAL(timeout()), this, SLOT(timerTimeOut())); 24 } 25 26 Camera::~Camera() 27 { 28 delete capture; 29 capture = NULL; 30 } 31 32 void Camera::selectCameraDevice(int index) 33 { 34 /* 如果有其他摄像头打开了,先释放 */ 35 if (capture->isOpened()) { 36 capture->release(); 37 } 38 39 /* 打开摄像头设备 */ 40 capture->open(index); 41 } 42 43 bool Camera::cameraProcess(bool bl) 44 { 45 if (bl) { 46 /* 为什么是 33?1000/33 约等于 30 帧,也就是一秒最多显示 30 帧 */ 47 timer->start(33); 48 } else { 49 timer->stop(); 50 } 51 /* 返回摄像头的状态 */ 52 return capture->isOpened(); 53 } 54 55 void Camera::timerTimeOut() 56 { 57 /* 如果摄像头没有打开,停止定时器,返回 */ 58 if (!capture->isOpened()) { 59 timer->stop(); 60 return; 61 } 62 63 static cv::Mat frame; 64 *capture >> frame; 65 if (frame.cols) 66 /* 发送图片信号 */ 67 emit readyImage(matToQImage(frame)); 68 } 69 70 QImage Camera::matToQImage(const cv::Mat &img) 71 { 72 /* USB 摄像头和 OV5640 等都是 RGB 三通道,不考虑单/四通道摄像头 */ 73 if(img.type() == CV_8UC3) { 74 /* 得到图像的的首地址 */ 75 const uchar *pimg = (const uchar*)img.data; 76 77 /* 以 img 构造图片 */ 78 QImage qImage(pimg, img.cols, img.rows, img.step, 79 QImage::Format_RGB888); 80 81 /* 在不改变实际图像数据的条件下,交换红蓝通道 */ 82 return qImage.rgbSwapped(); 83 } 84 85 /* 返回 QImage */ 86 return QImage(); 87 }
mainwindow.h 头文件代码如下。
/****************************************************************** Copyright © Deng Zhimao Co., Ltd. 1990-2021. All rights reserved. * @projectName 05_opencv_camera * @brief mainwindow.h * @author Deng Zhimao * @email 1252699831@qq.com * @net www.openedv.com
* @date 2021-03-17 *******************************************************************/ 1 #ifndef MAINWINDOW_H 2 #define MAINWINDOW_H 3 4 #include <QMainWindow> 5 #include <QVBoxLayout> 6 #include <QHBoxLayout> 7 #include <QComboBox> 8 #include <QPushButton> 9 #include <QVBoxLayout> 10 #include <QLabel> 11 #include <QScrollArea> 12 #include <QDebug> 13 14 class Camera; 15 16 class MainWindow : public QMainWindow 17 { 18 Q_OBJECT 19 20 public: 21 MainWindow(QWidget *parent = nullptr); 22 ~MainWindow(); 23 24 private: 25 /* 主容器,Widget 也可以当作一种容器 */ 26 QWidget *mainWidget; 27 28 /* 滚动区域,方便开发高分辨率 */ 29 QScrollArea *scrollArea; 30 31 /* 将采集到的图像使用 Widget 显示 */ 32 QLabel *displayLabel; 33 34 /* 界面右侧区域布局 */ 35 QHBoxLayout *hboxLayout; 36 37 /* 界面右侧区域布局 */ 38 QVBoxLayout *vboxLayout; 39 40 /* 界面右侧区域容器 */ 41 QWidget *rightWidget;42 43 /* 界面右侧区域显示拍照的图片 */ 44 QLabel *photoLabel; 45 46 /* 界面右侧区域摄像头设备下拉选择框 */ 47 QComboBox *comboBox; 48 49 /* 两个按钮,一个为拍照按钮,另一个是开启摄像头按钮 */ 50 QPushButton *pushButton[2]; 51 52 /* 拍照保存的照片 */ 53 QImage saveImage; 54 55 /* 摄像头设备 */ 56 Camera *camera; 57 58 /* 布局初始化 */ 59 void layoutInit(); 60 61 /* 扫描是否存在摄像头 */ 62 void scanCameraDevice(); 63 64 private slots: 65 /* 显示图像 */ 66 void showImage(const QImage&); 67 68 /* 设置按钮文本 */ 69 void setButtonText(bool); 70 71 /* 保存照片到本地 */ 72 void saveImageToLocal(); 73 }; 74 #endif // MAINWINDOW_H
mainwindow.cpp 源文件代码如下。
/****************************************************************** Copyright © Deng Zhimao Co., Ltd. 1990-2021. All rights reserved. * @projectName 05_opencv_camera * @brief mainwindow.cpp * @author Deng Zhimao * @email 1252699831@qq.com * @net www.openedv.com * @date 2021-03-17 *******************************************************************/
1 #include "mainwindow.h" 2 #include <QGuiApplication> 3 #include <QScreen> 4 #include <QFile> 5 #include <QPixmap> 6 #include <QBuffer> 7 #include "camera.h" 8 9 MainWindow::MainWindow(QWidget *parent) 10 : QMainWindow(parent) 11 { 12 /* 布局初始化 */ 13 layoutInit(); 14 15 /* 扫描摄像头 */ 16 scanCameraDevice(); 17 } 18 19 MainWindow::~MainWindow() 20 { 21 } 22 23 void MainWindow::layoutInit() 24 { 25 /* 获取屏幕的分辨率,Qt 官方建议使用这
26 * 种方法获取屏幕分辨率,防上多屏设备导致对应不上
27 * 注意,这是获取整个桌面系统的分辨率
28 */ 29 QList <QScreen *> list_screen = QGuiApplication::screens(); 30 31 /* 如果是 ARM 平台,直接设置大小为屏幕的大小 */ 32 #if __arm__ 33 /* 重设大小 */ 34 this->resize(list_screen.at(0)->geometry().width(), 35 list_screen.at(0)->geometry().height()); 36 #else 37 /* 否则则设置主窗体大小为 800x480 */ 38 this->resize(800, 480); 39 #endif 40 41 /* 实例化与布局,常规操作 */ 42 mainWidget = new QWidget(); 43 photoLabel = new QLabel(); 44 rightWidget = new QWidget(); 45 comboBox = new QComboBox(); 46 pushButton[0] = new QPushButton(); 47 pushButton[1] = new QPushButton(); 48 scrollArea = new QScrollArea(); 49 displayLabel = new QLabel(scrollArea); 50 vboxLayout = new QVBoxLayout(); 51 hboxLayout = new QHBoxLayout(); 52 53 vboxLayout->addWidget(photoLabel); 54 vboxLayout->addWidget(comboBox); 55 vboxLayout->addWidget(pushButton[0]); 56 vboxLayout->addWidget(pushButton[1]); 57 58 rightWidget->setLayout(vboxLayout); 59 60 hboxLayout->addWidget(scrollArea); 61 hboxLayout->addWidget(rightWidget); 62 mainWidget->setLayout(hboxLayout); 63 64 this->setCentralWidget(mainWidget); 65 66 pushButton[0]->setMaximumHeight(40); 67 pushButton[0]->setMaximumWidth(200); 68 69 pushButton[1]->setMaximumHeight(40); 70 pushButton[1]->setMaximumWidth(200); 71 72 comboBox->setMaximumHeight(40); 73 comboBox->setMaximumWidth(200); 74 photoLabel->setMaximumSize(100, 75); 75 scrollArea->setMinimumWidth(this->width() 76 - comboBox->width()); 77 78 /* 显示图像最大画面为 xx */ 79 displayLabel->setMinimumWidth(scrollArea->width() * 0.75); 80 displayLabel->setMinimumHeight(scrollArea->height() * 0.75); 81 scrollArea->setWidget(displayLabel); 82 83 /* 居中显示 */ 84 scrollArea->setAlignment(Qt::AlignCenter); 85 86 /* 自动拉伸 */ 87 photoLabel->setScaledContents(true); 88 displayLabel->setScaledContents(true); 89 90 /* 设置一些属性 */ 91 pushButton[0]->setText("拍照"); 92 pushButton[0]->setEnabled(false); 93 pushButton[1]->setText("开始"); 94 pushButton[1]->setCheckable(true); 95 96 /* 摄像头 */ 97 camera = new Camera(this); 98 99 /* 信号连接槽 */ 100 connect(camera, SIGNAL(readyImage(QImage)), 101 this, SLOT(showImage(QImage))); 102 connect(pushButton[1], SIGNAL(clicked(bool)), 103 camera, SLOT(cameraProcess(bool))); 104 connect(pushButton[1], SIGNAL(clicked(bool)), 105 this, SLOT(setButtonText(bool))); 106 connect(pushButton[0], SIGNAL(clicked()), 107 this, SLOT(saveImageToLocal())); 108 109 } 110 111 void MainWindow::scanCameraDevice() 112 { 113 /* 如果是 Windows 系统,一般是摄像头 0 */ 114 #if win32 115 comboBox->addItem("windows 摄像头 0"); 116 connect(comboBox, 117 SIGNAL(currentIndexChanged(int)), 118 camera, SLOT(selectCameraDevice(int))); 119 #else 120 /* QFile 文件指向/dev/video0 */ 121 QFile file("/dev/video0"); 122 123 /* 如果文件存在 */ 124 if (file.exists()) 125 comboBox->addItem("video0"); 126 else { 127 displayLabel->setText("无摄像头设备"); 128 return; 129 } 130 131 file.setFileName("/dev/video1"); 132 133 if (file.exists()) { 134 comboBox->addItem("video1"); 135 /* 开发板 ov5640 等设备是 1 */ 136 comboBox->setCurrentIndex(1); 137 } 138 139 file.setFileName("/dev/video2"); 140 141 if (file.exists()) 142 /* 开发板 USB 摄像头设备是 2 */ 143 comboBox->addItem("video2"); 144 145 #if !__arm__ 146 /* ubuntu 的 USB 摄像头一般是 0 */ 147 comboBox->setCurrentIndex(0); 148 #endif 149 150 connect(comboBox, 151 SIGNAL(currentIndexChanged(int)), 152 camera, SLOT(selectCameraDevice(int))); 153 #endif 154 } 155 156 void MainWindow::showImage(const QImage &image) 157 { 158 /* 显示图像 */ 159 displayLabel->setPixmap(QPixmap::fromImage(image)); 160 saveImage = image; 161 162 /* 判断图像是否为空,空则设置拍照按钮不可用 */ 163 if (!saveImage.isNull()) 164 pushButton[0]->setEnabled(true); 165 else 166 pushButton[0]->setEnabled(false); 167 } 168 169 void MainWindow::setButtonText(bool bl) 170 { 171 if (bl) { 172 /* 设置摄像头设备 */ 173 camera->selectCameraDevice(comboBox->currentIndex());174 pushButton[1]->setText("关闭"); 175 } else { 176 /* 若关闭了摄像头则禁用拍照按钮 */ 177 pushButton[0]->setEnabled(false); 178 pushButton[1]->setText("开始"); 179 } 180 } 181 182 void MainWindow::saveImageToLocal() 183 { 184 /* 判断图像是否为空 */ 185 if (!saveImage.isNull()) { 186 QString fileName = 187 QCoreApplication::applicationDirPath() + "/test.png"; 188 qDebug()<<"正在保存"<<fileName<<"图片,请稍候..."<<endl; 189 190 /* save(arg1,arg2,arg3)重载函数,arg1 代表路径文件名,
191 * arg2 保存的类型,arg3 代表保存的质量等级 */ 192 saveImage.save(fileName, "PNG", -1); 193 194 /* 设置拍照的图像为显示在 photoLabel 上 */ 195 photoLabel->setPixmap(QPixmap::fromImage(QImage(fileName))); 196 197 qDebug()<<"保存完成!"<<endl; 198 } 199 } 200
第 111~154 行,判断 linux 下的设备/dev/video*。细心的同学发现,这个程序是 Linux 下用
的。当然 Windows 也是可以使用 OpenCV 的,需要自己修改 pro 文件链接到 Windows 的 OpenCV
库-L 需要修改为-LD,Windows 下的库文件是 dll 类型,此外不考虑 macOS 系统,具体情况笔
者没得实验。
程序运行效果
选择合适的摄像头设备,(注意如果在 Ubuntu 使用 USB 摄像头,需要设置 USB 的兼容性
为 3.0 反之 2.0,具体需要看不同摄像头设备,点击连接摄像头到虚拟机。可以先使用 Ubuntu18.04
自带的茄子拍照软件,检测摄像头是否可用)。点击拍照,可以看程序输出的 Debug 信息,保
存照片的路径为当前可执行程序的路径,保存照片名称为 test.png,右上角显示保存照片的缩略
图,再次点击拍照则会替换已经保存过的照片。若想要保存多个照片可自行设计。
若在正点原子 I.MX6U 开发板上运行此程序,先插上摄像头,确保摄像头能用,注意不要
选择 video0,video0 是 NXP 的 pxp 驱动产生的节点,不是摄像头,否则会报错。I.MX6U 开发
板是单核 A7 的 CPU,性能有限,所以流畅度一般,还可以。但是在保存照片时会比 PC 电脑
慢好多,不过也不能太勉强这个 6ULL 芯片了啦,能拍照已经不错了,或者大家可以对保存照
片步骤进行优化,开启一个线程进行优化,剩下的交给大家了,大家可以的。
OpenCV 在不设置摄像头分辨率时会采用默认分辨率 640*480 30fps(绝大多数摄像头都是
支持这个分辨率)。USB 免驱摄像头可以使用下面的方法来设置分辨率。
capture->open(1);
capture ->set(CV_CAP_PROP_FRAME_WIDTH, 320);
capture ->set(CV_CAP_PROP_FRAME_HEIGHT, 240);
但是正点原子 6ULL 开发板上的 OV5640/OV2640/OV7725(不带 FIFO 款)摄像头就不可
以直接使用些方法设置采集分辨率了,因为驱动里设置分辨率的方法与标准的 V4L2 设置分辨
有些差异。也可以直接使用正点原子 I.MX6U 里的摄像头采集分辨率设置软件 camera_settings
直接设置,注意在处理图像中的 matToQImage 函数需要以确认的分辨率进行转换使用了。
总结,想要在 Qt 中使用 OpenCV,那么我们的开发板文件系统里或者 Ubuntu 系统必须要
有 OpenCV 的库。对于某些非通用的 USB 摄像头来说,因为驱动层限制不能直接使用 Qt 自带
的 QCamera 类。
相关文章:

QT开发笔记(Camera)
Camera 此章节例程适用于 Ubuntu 和正点原子 I.MX6U 开发板,不适用于 Windows(需要自行修改 才能适用 Windows,Windows 上的应用不在我们讨论范围)! 资源简介 正点原子 I.MX6U 开发板底板上有一路“CSI”摄像头接口。支持正点原…...
从C++的角度讲解C#容器
讲解C#容器的文章网上一搜一大把,作为一名C程序员如何高效学习C#容器呢,其实学语言如果能讲到这点就能触类旁通,举一反三,那效果是最好的问题市面上没有这样的书籍,那就跟着老白来一起从C的角度去讲解C#容器1.List<…...

React组件库实践:React + Typescript + Less + Rollup + Storybook
背景 原先在做低代码平台的时候,刚好有搭载React组件库的需求,所以就搞了一套通用的React组件库模版。目前通过这套模板也搭建过好几个组件库。 为了让这个模板更干净和通用,我把所有和低代码相关的代码都剔除了,只保留最纯粹的…...

c++ atomic
文章目录why atomic?sequentially consistent atomicRelaxed memory modelswhy atomic? 当我们有一片内存空间S,线程A正在往S里写数据,这个时候线程B突然往S中做了操作,导致线程A的操作结果变得不可预知(对线程A来说),这种情况换句话说叫做data race,我们一般的操作时上锁,在…...

要想孩子写作文没烦恼?建议家长这样做
说起语文学习,就不得不提作文。作为语文学习中的重中之重,作文写作一直是压在学生和家长身上的一块“心头大石”。发现很多孩子在写作文时,往往存在四大问题:写不出、不生动、流水账、太空洞。如今,孩子怕写作文&#…...

基于Python的高光谱图像分析教程
1、前言超光谱图像 (HSI) 分析因其在从农业到监控的各个领域的应用而成为人工智能 (AI) 研究的前沿领域之一。 该领域正在发表许多研究论文,这使它变得更加有趣! 和“对于初学者来说,在 HSI 上开始模式识别和机器学习是相当麻烦的”ÿ…...

【图神经网络】从0到1使用PyG手把手创建异构图
从0到1用PyG创建异构图异构图创建异构图电影评分数据集MovieLens建立二分图数据集转换为可训练的数据集建立异构图神经网络以OGB数据集为例HeteroData中常用的函数将简单图神经网络转换为异质图神经网络GraphGym的使用PyG中常用的卷积层参考资料在现实中需要对 多种类型的节点以…...

2023美赛春季赛思路分析汇总
将在本帖更新汇总2023美赛春季赛两个赛题思路,大家可以点赞收藏! 2023美赛春季赛各赛题全部解题参考思路资料模型代码等全部实时更新!第一时间获取全部美赛春季赛相关资料! 目前思路整理仅为部分,请大家耐心等待&…...

GPT4国内镜像站
GPT-4介绍GPT-4是OpenAI发布的最先进的大型语言模型,是ChatGPT模型的超级进化版本。与ChatGPT相比,GPT-4的推理能力、复杂问题的理解能力、写代码能力得到了极大的强化,是当前人工智能领域,最有希望实现通用人工智能的大模型。但G…...

代码随想录算法训练营第四十八天| 198 打家劫舍 213 打家劫舍II 337 打家劫舍III
代码随想录算法训练营第四十八天| 198 打家劫舍 213 打家劫舍II 337 打家劫舍III LeetCode 198 打家劫舍 题目: 198.打家劫舍 动规五部曲: 确定dp数组以及下标的含义 dp[i]:考虑下标i(包括i)以内的房屋,最多可以偷…...

飞桨DeepXDE用例验证及评估
在之前发布的文章中,我们介绍了飞桨全量支持业内优秀科学计算深度学习工具 DeepXDE。本期主要介绍基于飞桨动态图模式对 DeepXDE 中 PINN 方法用例实现、验证及评估的具体流程,同时提供典型环节的代码,旨在帮助大家更加高效地基于飞桨框架进行…...

telegram连接本地Proxy连接不上
1.ClashX开启允许局域网连接。 2.重启ClashX和Telegram...

【分布式版本控制系统Git】| 国内代码托管中心-Gitee、自建代码托管平台-GitLab
目录 一:国内代码托管中心-码云 1. 码云创建远程库 2. IDEA 集成码云 3. 码云复制 GitHub 项目 二:自建代码托管平台-GitLab 1. GitLab 安装 2. IDEA 集成 GitLab 一:国内代码托管中心-码云 众所周知,GitHub 服务器在国外&…...

【面试】BIO、NIO、AIO面试题
文章目录什么是IO在了解不同的IO之前先了解:同步与异步,阻塞与非阻塞的区别什么是BIO什么是NIO什么是AIO什么NettyBIO和NIO、AIO的区别IO流的分类按照读写的单位大小来分:按照实际IO操作来分:按照读写时是否直接与硬盘,…...

C语言实现拼图求解
题目: 有如下的八种拼图块,每块都是由八块小正方块构成, 这些拼图块刚好可以某种方式拼合放入给定的目标形状, 请以C或C++编程,自动求解 一种拼图方式 目标拼图: 本栏目适合想要深入了解无向图、深度优先算法、编程语句如何实现算法、想要去接拼图算法的小伙伴。...

python --获取本机屏幕分辨率
pywin32 方法一 使用 win32api.GetDeviceCaps() 方法来获取显示器的分辨率。 使用 win32api.GetDC() 方法获取整个屏幕的设备上下文句柄,然后使用 win32api.GetDeviceCaps() 方法获取水平和垂直方向的分辨率。最后需要调用 win32api.ReleaseDC() 方法释放设备上下…...

Java多态
目录 1.多态是什么? 2.多态的条件 3.重写 3.1重写的概念 3.2重写的作用 3.3重写的规则 4.向上转型与向下转型 4.1向上转型 4.2向下转型 5.多态的优缺点 5.1 优点 5.2 缺点 面向对象程序三大特性:封装、继承、多态。 1.多态是什么࿱…...

绝对路径和相对路径
1.绝对路径:从根目录为起点到某一个目录的路径 使用计算机时要找到需要的文件就必须知道文件的位置,表示文件的位置的方式就是路径,例如只要看到这个路径:c:/website/img/photo.jpg我们就知道photo.jpg文件是在c盘的website目录下…...

Linux第二次总结
Linux阶段总结 OSI模型:应用层、表示层、会话层、传输层、网络层、数据链路层、物理层 路由器的工作原理:最佳路径选择 三次握手四次挥手:... shell是翻译官把人类语言翻译成二进制语言 Tab作用:自动补齐、确认输入是否有误 …...

算法:贪婪算法、分而治之
算法:贪婪算法、分而治之 文章目录1.贪婪算法计数硬币实例12.分而治之分割/歇征服/解决合并/合并实例23.动态规划对照实例34.基本概念算法数据定义数据对象内置数据类型派生数据类型基本操作1.贪婪算法 设计算法以实现给定问题的最佳解决方案。在贪婪算法方法中&am…...

462. 最小操作次数使数组元素相等 II——【Leetcode每日一题】
462. 最小操作次数使数组元素相等 II 给你一个长度为 n 的整数数组 nums ,返回使所有数组元素相等需要的最小操作数。 在一次操作中,你可以使数组中的一个元素加 1 或者减 1 。 示例 1: 输入:nums [1,2,3] 输出:2 …...

对数据库的库及表的操作
全篇在MySQL操作下完成 在此之前,先介绍一下,字段、列类型及属性。 一、什么是字段、列类型、属性 (1)字段,一张表中列的名称;列类型,该列存储数据的类型;属性,描述列类型的特征。 …...

final类又没实现接口应该用哪一种代理, jdk动态代理还是cglib代理
jdk动态代理还是cglib代理🧙jdk动态代理和cglib代理的示例JDK动态代理原理CGLIB代理final类又没实现接口应该用哪一种代理, jdk动态代理还是cglib代理滚滚长江东逝水,浪花淘尽英雄。——唐代杨炯《临江仙》 jdk动态代理和cglib代理的示例 以下是一个使用…...

使用StaMPS_Visualizer
0 前言 StaMPS-Visualizer :由thho开发的用于可视化由StaMPS / MTI处理的DInSAR结果。 github地址:StaMPS-Visualizer 使用StaMPS_Visualizer需要配置好StaMPS,并安装好R和Rstudio Ubuntu中安装StaMPS StaMPS-Visualizer 安装步骤–在linux…...

高并发-高性能-高可用-结论版
文章目录上万的并发需要多少台web服务器一般单机能处理200请求,为何redis单机却能处理上万请求单线程每秒能处理(发送/响应)的http请求数三高的定义高并发的解决方案高性能的解决方案高可用的解决方案参考文章上万的并发需要多少台web服务器 …...

数智转型助力建筑业全产业链升级,你了解多少?
关于数智转型,指的是基于数字化技术和数据驱动的思维方式,将企业的管理、业务和服务进行全面的升级和改造,从而帮助实现企业的数字化转型和升级。通过数字技术和数据分析来提高企业的效率、创新能力和竞争力,进一步提高企业的市场…...

Python网络设备脚本中经常使用的connecthandler和telnetlib是什么意思?
你好,这里是网络技术联盟站。 在昨天的文章中,有小伙伴提到对这两天瑞哥提供的Python脚本中涉及的connecthandler和telnetlib两个模块不是太了解,想要学习一下: 今天瑞哥就安排上! 其实这两个模块是Python与网络设备…...

你真的会写 git commit message 吗?
作者:明明如月学长, CSDN 博客专家,蚂蚁集团高级 Java 工程师,《性能优化方法论》作者、《解锁大厂思维:剖析《阿里巴巴Java开发手册》》、《再学经典:《EffectiveJava》独家解析》专栏作者。 热门文章推荐…...

ISO文件内添加kickstart完成自动安装
目录 将待制作的centos iso文件挂载到/mnt/目录 将/mnt/下的所有文件复制到新的目录/tmp/mycentos 创建kickstart文件 修改启动文件 重新制作ISO文件 制作完成 kickstart可以实现根据配置自动安装操作系统,本文主要讲解如何让机器读取到iso文件后自动完成操作…...

SpringBoot 整合RabbitMq 自定义消息监听容器来实现消息批量处理
SpringBoot 整合RabbitMq 自定义消息监听容器来实现消息批量处理前言添加依赖配置文件编写监听器创建SimpleRabbitListenerContainerFactory发送消息前言 RabbitMQ是一种常用的消息队列,Spring Boot对其进行了深度的整合,可以快速地实现消息的发送和接收…...