OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 4131|回复: 0

《I.MX6U嵌入式Qt开发指南 V1.0》第十九章 Camera

[复制链接]

1118

主题

1129

帖子

2

精华

超级版主

Rank: 8Rank: 8

积分
4672
金钱
4672
注册时间
2019-5-8
在线时间
1224 小时
发表于 2021-7-19 12:14:58 | 显示全部楼层 |阅读模式
1)实验平台:正点原子阿尔法Linux开发板
2)  章节摘自【正点原子】《I.MX6U嵌入式Qt开发指南 V1.0》
3)购买链接:https://detail.tmall.com/item.htm?id=609033604451
4)全套实验源码+手册+视频下载地址:http://www.openedv.com/docs/boards/arm-linux/zdyz-i.mx6ull.html
5)正点原子官方B站:https://space.bilibili.com/394620890
6)正点原子阿尔法Linux交流群:1027879335 QQ群.png

原子哥.jpg

微信公众号.png



第十九章 Camera

此小节例程适用于Ubuntu和正点原子I.MX6U开发板,不适用于Windows(需要自行修改才能适用Windows,Windows上的应用不在我们讨论范围)!


19.1 资源简介
正点原子I.MX6U开发板底板上有一路“CSI”摄像头接口。支持正点原子的OV5640、OV2640和OV7725(不带FIFO)。同时有USB接口,可以接USB免驱摄像头。例程兼容USB摄像头与正点原子的OV5640、OV2640和OV7725摄像头。
出厂系统请更新到正点原子I.MX6U最新的出厂系统,在驱动层正点原子有对OV5640、OV2640和OV7725摄像头有维护、优化或者添加支持。
19.2 环境搭建
Qt里也有一个QCamera类。没错,确实可以使用这个QCamera类来开发摄像头。但是这个类在正点原子的I.MX6U开发板上此内核版本上不能使用OV5640、OV2640和OV7725,可以使用USB免驱摄像头。因为OV5640、OV2640和OV7725的驱动默认是YUYV数据,QCamera里读取的数据是RGB格式的数据,可能数据对不上就无法使用了!但是也不建议修改驱动的方法来使用QCamera,防止QCamera在某些方法上与驱动层次不对应,导致使用报错。
实际上我们使用V4l2编程就可以对摄像头进行编程,效果会比在Qt显示流畅,因为V4l2的数据直接可以显示在fb0(也就是屏上)。而经过Qt还需要在控件上处理,所以效率会慢一些!如果我们单单只顾着编程,而不考虑CPU性能的问题,最终结果出人所料!在正点原子I.MX6U开发板上或者说是嵌入式上,这种比较低性能的CPU对于处理图像等大数据还是比较吃力的。所以我们需要去优化,不同的编程方式,对数据的处理不同,写出来的效果也会不同!
下面主要介绍Qt + OpenCV调用摄像头,效果肯定不能与V4l2直接显示在fb0上比。在这个低端的CPU上显示效果还是比较好的,还能接受,流畅度一般。
要想在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(源码)进行下载。
第十九章 Camera1484.png
右键选择复制下载链接,用迅雷下载会比较快。下载完成后我们拷贝下载的文件到Ubuntu上进行解压。或者直接在正点原子的I.MX6U的光盘资料路径下找到开发板光盘A-基础资料/1、例程源码/7、第三方库源码/opencv-3.4.1.tar.gz。然后拷贝到Ubuntu下。
        如下图我们已经下载好文件,并拷贝下载好的文件到Ubuntu的家目录下。
第十九章 Camera1659.png
执行下面的指令进行解压。解压将会得到一个opencv-3.4.1文件夹,我们使用cd指令进入此文件夹。
  1. <font size="4">tar xf opencv-3.4.1.tar.gz
  2. </font><div><font size="4">cd opencv-3.4.1</font></div>
复制代码


第十九章 Camera1756.png
        安装cmake,用于生成编译所需要的文件。
  1. sudo apt-get install cmake  
复制代码


        新建一个build目录,并进入,用于编译生成的文件。
  1. mkdir build
  2. cd build
复制代码


第十九章 Camera1858.png
执行cmake配置编译。注意下面的指令“..”不要漏了!这里表示上一层目录。cmake会从上一层目录下找配置项,并配置到当前目录。
  1. cmake ..
复制代码


        在配置的过程中cmake会下载一些库,如 ippicv_2017u3_lnx_intel64_general_20170822.tgz,需要一段时间,请等待,如果不能下载成功请重复尝试。
        cmake配置成功如下图。
第十九章 Camera2045.png
执行make开始编译。输入下面的指令。
  1. make -j 16                                        // 以实际分配给虚拟机的核心数为准,最佳为分配给虚拟机核心数据的2倍。编者的虚拟机最大分配了16个核心,编者个人的电脑并不快,就是核心多,所以编译就快。编译完成耗时约5分钟。不要只输入make,否则将编译很久!需要加参数 -j n,n请根据个人虚拟机的实际情况。
复制代码


第十九章 Camera2216.png
第十九章 Camera2218.png
        执行下面的指令安装,安装到系统目录,需要加sudo权限。
  1. sudo make install
复制代码


第十九章 Camera2267.png
        安装完成如下。可以看到库被安装到/usr/local/lib下,头文件被安装在/usr/local/include下。
第十九章 Camera2330.png         
我们只需要知道安装的库路径和头文件路径即可在Qt里调用Ubuntu安装的OpenCV。头文件作用来编写程序,库路径用来运行程序时调用。我们只要在Qt的pro项目文件里指定这两个路径即可。
19.3 应用实例
请根据【正点原子】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)的文档搭建好交叉编译环境,用脚本启动,脚本有相应的环境变量,编译时会用到。
  1. /opt/Qt5.12.9/Tools/QtCreator/bin/qtcreator.sh &        
复制代码


        编写程序应使用我们搭建的ATK-I.MX6U套件编写,否则若选择了Desktop Qt 5.12.9 GCC 64bit,如果我们的Ubuntu没有安装OpenCV就会使用不了OpenCV。如果您在14.6.2小节已经安装过OpenCV,那么下面两个套件都可一起选。本次编者两个一起选,因为编者有USB摄像头可以在Ubutnu上使用OpenCV测试,编写的程序交叉编译后在I.MX6U开发板使用USB免驱摄像头或者正点原子OV5640/OV7725(不带FIFO款)/OV2640测试成功!
第十九章 Camera3075.png
        下面开始编写程序。首先我们需要在项目pro文件添加OpenCV库的支持及头文件路径。
05_opencv_camera.pro文件如下,添加以下内容,这里主要是判断交叉编译器的类型,然后链接到不同的头文件路径与库。
  1. 1   QT       += core gui
  2. 2
  3. 3   greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
  4. 4
  5. 5   CONFIG += c++11
  6. 6
  7. 7   # The following define makes your compiler emit warnings if you use
  8. 8   # any Qt feature that has been marked deprecated (the exact warnings
  9. 9   # depend on your compiler). Please consult the documentation of the
  10. 10  # deprecated API in order to know how to port your code away from it.
  11. 11  DEFINES += QT_DEPRECATED_WARNINGS
  12. 12
  13. 13  # You can also make your code fail to compile if it uses deprecated APIs.
  14. 14  # In order to do so, uncomment the following line.
  15. 15  # You can also select to disable deprecated APIs only up to a certain version of Qt.
  16. 16  #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0
  17. 17
  18. 18  TARGET_ARCH = ${QT_ARCH}
  19. 19  contains(TARGET_ARCH, arm){
  20. 20      CONFIG += link_pkgconfig
  21. 21      PKGCONFIG += opencv
  22. 22      INCLUDEPATH += /opt/fsl-imx-x11/4.1.15-2.1.0/sysroots/cortexa7hf-neon-poky-linux-gnueabi/usr/include
  23. 23  } else {
  24. 24      LIBS += -L/usr/local/lib \
  25. 25              -lopencv_core \
  26. 26              -lopencv_highgui \
  27. 27              -lopencv_imgproc \
  28. 28              -lopencv_videoio \
  29. 29              -lopencv_imgcodecs
  30. 30
  31. 31      #INCLUDEPATH可写可不写,系统会到找到此路径
  32. 32      INCLUDEPATH += /usr/local/include
  33. 33  }
  34. 34
  35. 35  SOURCES += \
  36. 36      camera.cpp \
  37. 37      main.cpp \
  38. 38      mainwindow.cpp
  39. 39
  40. 40  HEADERS += \
  41. 41      camera.h \
  42. 42      mainwindow.h
  43. 43
  44. 44  # Default rules for deployment.
  45. 45  qnx: target.path = /tmp/${TARGET}/bin
  46. 46  else: unix:!android: target.path = /opt/${TARGET}/bin
  47. 47  !isEmpty(target.path): INSTALLS += target
复制代码


第18行,获取编译器的类型。
第19行,判断交叉编译器的类型是否为arm。
第22行,arm对应opencv的头文件路径,可以不写,编译不会报错,但是我们想查看对应的头文件,就不得不包括这个路径了,否则跳转不过去!
第24~32行,添加库的支持。-L后面指的是库文件路径,-l后面的是相关库参数(l是大字母“L”的小写字母“l”,不是一),如果不会写库的名称,可以参考Ubuntu的安装路径下的/usr/local/lib/pkgconfig/opencv.pc文件。
camera.h文件,此文件声明了一个Camera类,其内容如下,比较简单。
  1. 9   #ifndef CAMERA_H
  2. 10  #define CAMERA_H
  3. 11
  4. 12  #include <QImage>
  5. 13  #include <QTimer>
  6. 14  /* 使用命名空间cv下的VideoCapture与Mat类 */
  7. 15  namespace cv {
  8. 16  class VideoCapture;
  9. 17  class Mat;
  10. 18  }
  11. 19
  12. 20  class Camera : public QObject
  13. 21  {
  14. 22      Q_OBJECT
  15. 23  public:
  16. 24      explicit Camera(QObject *parent = nullptr);
  17. 25      ~Camera();
  18. 26
  19. 27  signals:
  20. 28      /* 声明信号,用于传递有图片信号时显示图像 */
  21. 29      void readyImage(const QImage&);
  22. 30
  23. 31  public slots:
  24. 32      /* 用于开启定时器 */
  25. 33      bool cameraProcess(bool);
  26. 34
  27. 35      /* 选择摄像头 */
  28. 36      void selectCameraDevice(int);
  29. 37
  30. 38  private slots:
  31. 39      /* 定时器时间到处理函数,发送图像数据信号 */
  32. 40      void timerTimeOut();
  33. 41
  34. 42  private:
  35. 43      /* 声明OpenCV的cv命名空间下的VideoCapture对象 */
  36. 44      cv::VideoCapture * capture;
  37. 45
  38. 46      /* 定时器 */
  39. 47      QTimer * timer;
  40. 48
  41. 49      /* 图像转换处理函数 */
  42. 50      QImage matToQImage(const cv::Mat&);
  43. 51  };
  44. 52
  45. 53  #endif // CAMERA_H
  46. 54
复制代码


camera.cpp类的定义如下。
  1. 9   #include "camera.h"
  2. 10  #include "opencv2/core/core.hpp"
  3. 11  #include "opencv2/highgui/highgui.hpp"
  4. 12  #include <QImage>
  5. 13  #include <QDebug>
  6. 14
  7. 15  Camera::Camera(QObject *parent) :
  8. 16      QObject(parent)
  9. 17  {
  10. 18      /* 实例化 */
  11. 19      capture = new cv::VideoCapture();
  12. 20      timer = new QTimer(this);
  13. 21
  14. 22      /* 信号槽连接 */
  15. 23      connect(timer, SIGNAL(timeout()), this, SLOT(timerTimeOut()));
  16. 24  }
  17. 25
  18. 26  Camera::~Camera()
  19. 27  {
  20. 28      delete capture;
  21. 29      capture = NULL;
  22. 30  }
  23. 31
  24. 32  void Camera::selectCameraDevice(int index)
  25. 33  {
  26. 34      /* 如果有其他摄像头打开了,先释放 */
  27. 35      if (capture->isOpened()) {
  28. 36          capture->release();
  29. 37      }
  30. 38
  31. 39      /* 打开摄像头设备 */
  32. 40      capture->open(index);
  33. 41  }
  34. 42
  35. 43  bool Camera::cameraProcess(bool bl)
  36. 44  {
  37. 45      if (bl) {
  38. 46          /* 为什么是33?1000/33约等于30帧,也就是一秒最多显示30帧  */
  39. 47          timer->start(33);
  40. 48      } else {
  41. 49          timer->stop();
  42. 50      }
  43. 51      /* 返回摄像头的状态 */
  44. 52      return capture->isOpened();
  45. 53  }
  46. 54
  47. 55  void Camera::timerTimeOut()
  48. 56  {
  49. 57      /* 如果摄像头没有打开,停止定时器,返回 */
  50. 58      if (!capture->isOpened()) {
  51. 59          timer->stop();
  52. 60          return;
  53. 61      }
  54. 62
  55. 63      static cv::Mat frame;
  56. 64      *capture >> frame;
  57. 65      if (frame.cols)
  58. 66          /* 发送图片信号 */
  59. 67          emit readyImage(matToQImage(frame));
  60. 68  }
  61. 69
  62. 70  QImage Camera::matToQImage(const cv::Mat &img)
  63. 71  {
  64. 72      /* USB摄像头和OV5640等都是RGB三通道,不考虑单/四通道摄像头 */
  65. 73      if(img.type() == CV_8UC3) {
  66. 74          /* 得到图像的的首地址 */
  67. 75          const uchar *pimg = (const uchar*)img.data;
  68. 76
  69. 77          /* 以img构造图片 */
  70. 78          QImage qImage(pimg, img.cols, img.rows, img.step,
  71. 79                        QImage::Format_RGB888);
  72. 80
  73. 81          /* 在不改变实际图像数据的条件下,交换红蓝通道 */
  74. 82          return qImage.rgbSwapped();
  75. 83      }
  76. 84
  77. 85      /* 返回QImage */
  78. 86      return QImage();
  79. 87  }
复制代码


        mainwindow.h头文件代码如下。
   
  1. /******************************************************************
  2.     Copyright &#169; Deng Zhimao Co., Ltd. 1990-2021. All rights reserved.
  3.     * @projectName   05_opencv_camera
  4.     * @brief         mainwindow.h
  5.     * [url=home.php?mod=space&uid=90321]@Author[/url]        Deng Zhimao
  6.     * [url=home.php?mod=space&uid=55957]@EMAIL[/url]         <a href="mailto:1252699831@qq.com">1252699831@qq.com</a>
  7.     * [url=home.php?mod=space&uid=28414]@net[/url]            <a href="www.openedv.com" target="_blank">www.openedv.com</a>
  8.     * @date           2021-03-17
  9.     *******************************************************************/
  10. 1   #ifndef MAINWINDOW_H
  11. 2   #define MAINWINDOW_H
  12. 3
  13. 4   #include <QMainWindow>
  14. 5   #include <QVBoxLayout>
  15. 6   #include <QHBoxLayout>
  16. 7   #include <QComboBox>
  17. 8   #include <QPushButton>
  18. 9   #include <QVBoxLayout>
  19. 10  #include <QLabel>
  20. 11  #include <QScrollArea>
  21. 12  #include <QDebug>
  22. 13
  23. 14  class Camera;
  24. 15
  25. 16  class MainWindow : public QMainWindow
  26. 17  {
  27. 18      Q_OBJECT
  28. 19
  29. 20  public:
  30. 21      MainWindow(QWidget *parent = nullptr);
  31. 22      ~MainWindow();
  32. 23
  33. 24  private:
  34. 25      /* 主容器,Widget也可以当作一种容器 */
  35. 26      QWidget *mainWidget;
  36. 27
  37. 28      /* 滚动区域,方便开发高分辨率 */
  38. 29      QScrollArea *scrollArea;
  39. 30
  40. 31      /* 将采集到的图像使用Widget显示 */
  41. 32      QLabel *displayLabel;
  42. 33
  43. 34      /* 界面右侧区域布局 */
  44. 35      QHBoxLayout *hboxLayout;
  45. 36
  46. 37      /* 界面右侧区域布局 */
  47. 38      QVBoxLayout *vboxLayout;
  48. 39
  49. 40      /* 界面右侧区域容器 */
  50. 41      QWidget *rightWidget;
  51. 42
  52. 43      /* 界面右侧区域显示拍照的图片 */
  53. 44      QLabel *photoLabel;
  54. 45
  55. 46      /* 界面右侧区域摄像头设备下拉选择框 */
  56. 47      QComboBox *comboBox;
  57. 48
  58. 49      /* 两个按钮,一个为拍照按钮,另一个是开启摄像头按钮 */
  59. 50      QPushButton *pushButton[2];
  60. 51
  61. 52      /* 拍照保存的照片 */
  62. 53      QImage saveImage;
  63. 54
  64. 55      /* 摄像头设备 */
  65. 56      Camera *camera;
  66. 57
  67. 58      /* 布局初始化 */
  68. 59      void layoutInit();
  69. 60
  70. 61      /* 扫描是否存在摄像头 */
  71. 62      void scanCameraDevice();
  72. 63
  73. 64  private slots:
  74. 65      /* 显示图像 */
  75. 66      void showImage(const QImage&);
  76. 67
  77. 68      /* 设置按钮文本 */
  78. 69      void setButtonText(bool);
  79. 70
  80. 71      /* 保存照片到本地 */
  81. 72      void saveImageToLocal();
  82. 73  };
  83. 74  #endif // MAINWINDOW_H
复制代码

        mainwindow.cpp源文件代码如下。
   
  1. /******************************************************************
  2.     Copyright &#169; Deng Zhimao Co., Ltd. 1990-2021. All rights reserved.
  3.     * @projectName   05_opencv_camera
  4.     * @brief         mainwindow.cpp
  5.     * @author        Deng Zhimao
  6.     * @email         <a href="mailto:1252699831@qq.com">1252699831@qq.com</a>
  7.     * @net            <a href="www.openedv.com" target="_blank">www.openedv.com</a>
  8.     * @date           2021-03-17
  9.     *******************************************************************/
  10. 1   #include "mainwindow.h"
  11. 2   #include <QGuiApplication>
  12. 3   #include <QScreen>
  13. 4   #include <QFile>
  14. 5   #include <QPixmap>
  15. 6   #include <QBuffer>
  16. 7   #include "camera.h"
  17. 8  
  18. 9   MainWindow::MainWindow(QWidget *parent)
  19. 10      : QMainWindow(parent)
  20. 11  {
  21. 12      /* 布局初始化 */
  22. 13      layoutInit();
  23. 14
  24. 15      /* 扫描摄像头 */
  25. 16      scanCameraDevice();
  26. 17  }
  27. 18
  28. 19  MainWindow::~MainWindow()
  29. 20  {
  30. 21  }
  31. 22
  32. 23  void MainWindow::layoutInit()
  33. 24  {
  34. 25      /* 获取屏幕的分辨率,Qt官方建议使用这
  35. 26       * 种方法获取屏幕分辨率,防上多屏设备导致对应不上
  36. 27       * 注意,这是获取整个桌面系统的分辨率
  37. 28       */
  38. 29      QList <QScreen *> list_screen =  QGuiApplication::screens();
  39. 30
  40. 31      /* 如果是ARM平台,直接设置大小为屏幕的大小 */
  41. 32  #if __arm__
  42. 33      /* 重设大小 */
  43. 34      this->resize(list_screen.at(0)->geometry().width(),
  44. 35                   list_screen.at(0)->geometry().height());
  45. 36  #else
  46. 37      /* 否则则设置主窗体大小为800x480 */
  47. 38      this->resize(800, 480);
  48. 39  #endif
  49. 40
  50. 41      /* 实例化与布局,常规操作 */
  51. 42      mainWidget = new QWidget();
  52. 43      photoLabel = new QLabel();
  53. 44      rightWidget = new QWidget();
  54. 45      comboBox = new QComboBox();
  55. 46      pushButton[0] = new QPushButton();
  56. 47      pushButton[1] = new QPushButton();
  57. 48      scrollArea = new QScrollArea();
  58. 49      displayLabel = new QLabel(scrollArea);
  59. 50      vboxLayout = new QVBoxLayout();
  60. 51      hboxLayout = new QHBoxLayout();
  61. 52
  62. 53      vboxLayout->addWidget(photoLabel);
  63. 54      vboxLayout->addWidget(comboBox);
  64. 55      vboxLayout->addWidget(pushButton[0]);
  65. 56      vboxLayout->addWidget(pushButton[1]);
  66. 57
  67. 58      rightWidget->setLayout(vboxLayout);
  68. 59
  69. 60      hboxLayout->addWidget(scrollArea);
  70. 61      hboxLayout->addWidget(rightWidget);
  71. 62      mainWidget->setLayout(hboxLayout);
  72. 63
  73. 64      this->setCentralWidget(mainWidget);
  74. 65
  75. 66      pushButton[0]->setMaximumHeight(40);
  76. 67      pushButton[0]->setMaximumWidth(200);
  77. 68
  78. 69      pushButton[1]->setMaximumHeight(40);
  79. 70      pushButton[1]->setMaximumWidth(200);
  80. 71
  81. 72      comboBox->setMaximumHeight(40);
  82. 73      comboBox->setMaximumWidth(200);
  83. 74      photoLabel->setMaximumSize(100, 75);
  84. 75      scrollArea->setMinimumWidth(this->width()
  85. 76                                  - comboBox->width());
  86. 77
  87. 78      /* 显示图像最大画面为xx */
  88. 79      displayLabel->setMinimumWidth(scrollArea->width() * 0.75);
  89. 80      displayLabel->setMinimumHeight(scrollArea->height() * 0.75);
  90. 81      scrollArea->setWidget(displayLabel);
  91. 82
  92. 83      /* 居中显示 */
  93. 84      scrollArea->setAlignment(Qt::AlignCenter);
  94. 85
  95. 86      /* 自动拉伸 */
  96. 87      photoLabel->setScaledContents(true);
  97. 88      displayLabel->setScaledContents(true);
  98. 89
  99. 90      /* 设置一些属性 */
  100. 91      pushButton[0]->setText("拍照");
  101. 92      pushButton[0]->setEnabled(false);
  102. 93      pushButton[1]->setText("开始");
  103. 94      pushButton[1]->setCheckable(true);
  104. 95
  105. 96      /* 摄像头 */
  106. 97      camera = new Camera(this);
  107. 98
  108. 99      /* 信号连接槽 */
  109. 100     connect(camera, SIGNAL(readyImage(QImage)),
  110. 101             this, SLOT(showImage(QImage)));
  111. 102     connect(pushButton[1], SIGNAL(clicked(bool)),
  112. 103             camera, SLOT(cameraProcess(bool)));
  113. 104     connect(pushButton[1], SIGNAL(clicked(bool)),
  114. 105             this, SLOT(setButtonText(bool)));
  115. 106     connect(pushButton[0], SIGNAL(clicked()),
  116. 107             this, SLOT(saveImageToLocal()));
  117. 108
  118. 109 }
  119. 110
  120. 111 void MainWindow::scanCameraDevice()
  121. 112 {
  122. 113     /* 如果是Windows系统,一般是摄像头0 */
  123. 114 #if win32
  124. 115     comboBox->addItem("windows摄像头0");
  125. 116     connect(comboBox,
  126. 117             SIGNAL(currentIndexChanged(int)),
  127. 118             camera, SLOT(selectCameraDevice(int)));
  128. 119 #else
  129. 120     /* QFile文件指向/dev/video0 */
  130. 121     QFile file("/dev/video0");
  131. 122
  132. 123     /* 如果文件存在 */
  133. 124     if (file.exists())
  134. 125         comboBox->addItem("video0");
  135. 126     else {
  136. 127         displayLabel->setText("无摄像头设备");
  137. 128         return;
  138. 129     }
  139. 130
  140. 131     file.setFileName("/dev/video1");
  141. 132
  142. 133     if (file.exists()) {
  143. 134         comboBox->addItem("video1");
  144. 135         /* 开发板ov5640等设备是1 */
  145. 136         comboBox->setCurrentIndex(1);
  146. 137     }
  147. 138
  148. 139     file.setFileName("/dev/video2");
  149. 140
  150. 141     if (file.exists())
  151. 142         /* 开发板USB摄像头设备是2 */
  152. 143         comboBox->addItem("video2");
  153. 144
  154. 145 #if !__arm__
  155. 146     /* ubuntu的USB摄像头一般是0 */
  156. 147     comboBox->setCurrentIndex(0);
  157. 148 #endif
  158. 149
  159. 150     connect(comboBox,
  160. 151             SIGNAL(currentIndexChanged(int)),
  161. 152             camera, SLOT(selectCameraDevice(int)));
  162. 153 #endif
  163. 154 }
  164. 155
  165. 156 void MainWindow::showImage(const QImage &image)
  166. 157 {
  167. 158     /* 显示图像 */
  168. 159     displayLabel->setPixmap(QPixmap::fromImage(image));
  169. 160     saveImage = image;
  170. 161
  171. 162     /* 判断图像是否为空,空则设置拍照按钮不可用 */
  172. 163     if (!saveImage.isNull())
  173. 164         pushButton[0]->setEnabled(true);
  174. 165     else
  175. 166         pushButton[0]->setEnabled(false);
  176. 167 }
  177. 168
  178. 169 void MainWindow::setButtonText(bool bl)
  179. 170 {
  180. 171     if (bl) {
  181. 172         /* 设置摄像头设备 */
  182. 173         camera->selectCameraDevice(comboBox->currentIndex());
  183. 174         pushButton[1]->setText("关闭");
  184. 175     } else {
  185. 176         /* 若关闭了摄像头则禁用拍照按钮 */
  186. 177         pushButton[0]->setEnabled(false);
  187. 178         pushButton[1]->setText("开始");
  188. 179     }
  189. 180 }
  190. 181
  191. 182 void MainWindow::saveImageToLocal()
  192. 183 {
  193. 184     /* 判断图像是否为空 */
  194. 185     if (!saveImage.isNull()) {
  195. 186         QString fileName =
  196. 187                 QCoreApplication::applicationDirPath() + "/test.png";
  197. 188         qDebug()<<"正在保存"<<fileName<<"图片,请稍候..."<<endl;
  198. 189
  199. 190         /* save(arg1,arg2,arg3)重载函数,arg1代表路径文件名,
  200. 191          * arg2保存的类型,arg3代表保存的质量等级 */
  201. 192         saveImage.save(fileName, "PNG", 1);
  202. 193
  203. 194         /* 设置拍照的图像为显示在photoLabel上 */
  204. 195         photoLabel->setPixmap(QPixmap::fromImage(QImage(fileName)));
  205. 196
  206. 197         qDebug()<<"保存完成!"<<endl;
  207. 198     }
  208. 199 }
  209. 200
复制代码

        第111~154行,判断linux下的设备/dev/video*。细心的同学发现,这个程序是Linux下用的。当然Windows也是可以使用OpenCV的,需要自己修改pro文件链接到Windows的OpenCV库-L需要修改为-LD,Windows下的库文件是dll类型,此外不考虑macOS系统,具体情况编者没得实验。
19.4 程序运行效果
第十九章 Camera16123.png
选择合适的摄像头设备,(注意如果在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免驱摄像头可以使用下面的方法来设置分辨率。
  1. capture->open(1);
  2. capture ->set(CV_CAP_PROP_FRAME_WIDTH, 320);
  3. 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类。
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-25 18:38

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表