前言

1.在做图像处理开发中,比例做目标跟踪识别的时候,用OpenCV一直在处理摄像头传入的数据,有时候会出现界面卡死或者未响应的状态,这是因为事件循环一直等待处理函数的返回而导致阻塞事件循环,这样一来GUI线程所有的绘制和交互都被阻塞在事件队列中,无法执行重绘等事件,整个程序就失去响应了。
2.在这种状态下,为了保证程序的正常运行,最好的方法是把费时的数据处理函数放到别一个线程,处理完成之后再把结果返回给主线程。
在Qt界面中,主线程只要做界面的相关绘制就可以了。
3.在Qt里面,开多线程有几种方法,其中一种是继承QThread类之后重写run函数,还有一种是把继承于QObject的类转移到一个Thread里,后面这种是Qt官方在Qt4.8之后推荐的用法。
4.我这里使用QThread打开一个摄像头,之后用信号把每一帧图像传回主线程显示。

代码

CameraThread.h

#ifndef CAMERATHREAD_H
#define CAMERATHREAD_H
#include <QThread>
#include <QDebug>
#include <vector>
#include <QString>
#include <opencv2/opencv.hpp>class CameraThread : public QThread
{Q_OBJECTpublic:void stop();explicit CameraThread(QObject *parent = 0);cv::VideoCapture cv_cap;int camera_index;cv::Mat cv_src;protected:void run();private:volatile bool stopped;signals:void getImage(const cv::Mat&);public slots:};#endif // CAMERATHREAD_H

CameraThread.cpp

#include "CameraThread.h"CameraThread::CameraThread(QObject *parent) :QThread(parent)
{stopped = false;
}void CameraThread::run()
{qDebug() << "Current thread:" << QThread::currentThreadId();if (!cv_cap.isOpened()){cv_cap.open(0);}while (!stopped){cv_cap >> cv_src;if(!cv_src.data){continue;}emit getImage(cv_src);cv_src.release();}cv_cap.release();
}void CameraThread::stop()
{stopped = true;
}

调用代码:
Camera.cpp

#include "Camera.h"Camera::Camera(QWidget *parent): QMainWindow(parent)
{ui.setupUi(this);scene = new QGraphicsScene;//不是QT的类型要注册信号qRegisterMetaType<cv::Mat>("cv::Mat");connect(ui.actionCamera, SIGNAL(triggered()), this, SLOT(openCamera()));connect(ui.actionClose, SIGNAL(triggered()), this, SLOT(closeCamera()));
}void Camera::openCamera()
{thread = new CameraThread();connect(thread, SIGNAL(getImage(cv::Mat)), this, SLOT(getImage(cv::Mat)));thread->start();
}void Camera::closeCamera()
{if (thread->isRunning()){thread->stop();      thread->destroyed();}ui.DisplayLabel->close();
}void Camera::getImage(cv::Mat image)
{qt_image = MatImageToQimage(image);qt_pixmap = QPixmap::fromImage(qt_image);ui.DisplayLabel->setPixmap(qt_pixmap);displayImage(ui.DisplayLabel, qt_pixmap);ui.DisplayLabel->show();
}//显示图片到label窗口
void Camera::displayImage(QLabel *label, QPixmap &pixmap)
{//对齐方式,水平与垂直label->setAlignment(Qt::AlignLeft);//图像自适应窗口大小QSize imageSize = pixmap.size();QSize labelSize = label->size();double widthRatio = 1.0*imageSize.width() / labelSize.width();double heightRatio = 1.0*imageSize.height() / labelSize.height();if (widthRatio > heightRatio){pixmap = pixmap.scaledToWidth(labelSize.width());}else{pixmap = pixmap.scaledToHeight(labelSize.height());}//这个设置是整个图片跟着窗口改变,铺满label->setScaledContents(true);//label->resize(QSize(pixmap.width(),pixmap.height()));label->setPixmap(pixmap);
}
//Mat转成QImage
QImage Camera::MatImageToQimage(const cv::Mat &src)
{//CV_8UC1 8位无符号的单通道---灰度图片if (src.type() == CV_8UC1){//使用给定的大小和格式构造图像//QImage(int width, int height, Format format)QImage qImage(src.cols, src.rows, QImage::Format_Indexed8);//扩展颜色表的颜色数目qImage.setColorCount(256);//在给定的索引设置颜色for (int i = 0; i < 256; i++){//得到一个黑白图qImage.setColor(i, qRgb(i, i, i));}//复制输入图像,data数据段的首地址uchar *pSrc = src.data;//for (int row = 0; row < src.rows; row++){//遍历像素指针uchar *pDest = qImage.scanLine(row);//从源src所指的内存地址的起始位置开始拷贝n个//字节到目标dest所指的内存地址的起始位置中memcmp(pDest, pSrc, src.cols);//图像层像素地址pSrc += src.step;}return qImage;}//为3通道的彩色图片else if (src.type() == CV_8UC3){//得到图像的的首地址const uchar *pSrc = (const uchar*)src.data;//以src构造图片QImage qImage(pSrc, src.cols, src.rows, src.step, QImage::Format_RGB888);//在不改变实际图像数据的条件下,交换红蓝通道return qImage.rgbSwapped();}//四通道图片,带Alpha通道的RGB彩色图像else if (src.type() == CV_8UC4){const uchar *pSrc = (const uchar*)src.data;QImage qImage(pSrc, src.cols, src.rows, src.step, QImage::Format_ARGB32);//返回图像的子区域作为一个新图像return qImage.copy();}else{return QImage();}
}

Qt与OpenCV编程:在子线程打开摄像头用主线程显示相关推荐

  1. java 子线程退出_java – 在子线程完成执行之前主线程将退出吗?

    我读了2篇文章 在上面的文章中,在"线程终止"段中,它在Red中声明"如果父线程终止,它的所有子线程也会终止". 在上面的文章中,该页面的最后一行指出" ...

  2. Unity C# 子线程Action发送到主线程执行

    今天去面试..面试官竟然说子线程的Action不能发送到主线程执行... ...废话不说上干货 using System.Collections; using System.Collections.G ...

  3. 多线程遇到的问题:(2)子线程未运行完 主线程结束了

    问题: 用@Test测试多线程接口时,启动服务抛出异常: Singleton bean creation not allowed while singletons of this factory ar ...

  4. Android中Handler消息传递机制应用之子线程不允许操作主线程的组件

    场景 进程 一个Android应用就是一个一个进程,每个应用在各自的进程中运行. 线程 比进程更小的独立运行的基本单位,一个进程可以包含多个线程. 要求 一个TextView和一个Button,点击B ...

  5. UnityThread子线程使用只能在主线程中调用的函数或Unity API

    Unity的Socket网络编程中,为了防止程序卡死,一般使用多线程来监听端口,当收到来自客户端的消息时,需要显示在界面上.但是如果直接在子线程中操作Unity的界面或物体会报错.国外一个大神写了一个 ...

  6. python 主程序等待 子线程_Python多线程中主线程等待所有子线程结束的方法

    Python多线程中主线程等待所有子线程结束的方法 发布时间:2020-07-30 14:39:04 来源:亿速云 阅读:77 作者:小猪 这篇文章主要讲解了Python多线程中主线程等待所有子线程结 ...

  7. WPF 子窗打开时在父窗显示蒙板

    WPF 子窗打开时在父窗显示蒙板 控件名:WindowHelpers 作   者:WPFDevelopersOrg - 驚鏵 原文链接[1]:https://github.com/WPFDevelop ...

  8. java 主线程_Java中的主线程 - Break易站

    Java 多线程 Java为多线程编程提供内置支持.多线程程序包含两个或多个可以并发运行的部分.这样的程序的每个部分称为线程,每个线程定义一个单独的执行路径. Java中的主线程 当Java程序启动时 ...

  9. Qt自定义事件实现及子线程向主线程传送事件消息

    近期在又一次学习Qt的时候,由于要涉及到子线程与主线程传递消息,所以便琢磨了一下.顺便把有用的记录下来,方便自己以后查询及各位同仁的參考! 特此声明,本篇博文主要讲述有用的,也就是直接说明怎么实现,就 ...

最新文章

  1. 如何利用 nbconvert将 IPYNB文档转换 Markdown文档?
  2. 【正一专栏】亚冠抽签点评——上港令人期待
  3. Dwg图纸属性的读取
  4. DRBD+HeartBeat+NFS 架构
  5. 【转】Android 轻松实现语音识别
  6. MSChart中转义符
  7. uva 1612——Guess
  8. python求组合数_求组合数的算法_Cppowboy's Blog - SegmentFault 思否
  9. 《统计学习方法》读书笔记——朴素贝叶斯法(公式推导+代码实现)
  10. 如何设置Mac定时重启
  11. 推荐一个Oracle数据库学习网站
  12. Lua教程(二):C++和Lua相互传递数据示例
  13. 有专门收C语言答案的软件吗,C语言二级考试题库APP
  14. Can't update 分支名 has no tracked branch
  15. ipv4v6双栈技术_什么是IPv6双栈技术
  16. Activity启动流程(二)system_server进程处理启动Activity请求
  17. 如何判断iPhone5 iPhone 5S iPhone6 iPhone6 plus?
  18. 解决Windows密码错误无法进入系统的问题
  19. ceph (luminous 版) primary affinity 管理
  20. html5横竖条纹背景,CSS制作Web页面条纹背景样式的介绍

热门文章

  1. 用leda没有java enterprise选项_Visual Studio 支持 Java?谣言止于智者
  2. 数据结构实验之数组二:稀疏矩阵
  3. opencv 运动目标检测
  4. JQuery 总结(7) index() data() each() 选项卡 表单验证
  5. 你真的会玩SQL吗?内连接、外连接
  6. Java 集合类图(转)
  7. 对map集合进行排序
  8. 程序员必知必会之Email篇
  9. Scala基础教程(二):数据类型、变量
  10. 信息系统项目管理师-风险管理知识点