一、QT(WIN10)安裝
1.首先下載QT(VS有對(duì)應(yīng)的QT)
下載鏈接
windows程序的后綴是.exe
Ubuntu程序的后綴是.run
2.安裝QT
按照安裝指示操作、注冊(cè)QT,然后出現(xiàn)”選擇“界面時(shí)勾選“MinGW 7.3.0 64-bit”,“MSVC 2017 64-bit”;點(diǎn)擊“Developer and Designer Tools”前的尖號(hào),打開(kāi)其中選項(xiàng),勾選“MinGW 7.3.0 64-bit”。
二、將QT加載到VS中
在VS"工具"→"擴(kuò)展與更新"→"聯(lián)機(jī)"中搜索“QT”并下載,重啟生效
三、QT設(shè)置
1.在VS"Qt Vs Tools"→"QT Versions"中添加"msvc2017_64"qmake的路徑
2.在"General"→"QT Designer"中將"False"改為"True"
四、QT程序打包
1.新建QT Widges項(xiàng)目,Base class也選擇"QWidget"類(lèi)(QMainWindow是一個(gè)含有菜單的窗口、QDialog是對(duì)話框、QWidget是不確定的窗口)
2.先在VS中使用Release模式發(fā)布,在x64中找到生成的exe
3.在空白處"shift"+右鍵打開(kāi)Windows PowerShell模式,使用QT自帶的搜索程序QT\mingw73_64\bin\windeployqt.exe將exe需要的動(dòng)態(tài)庫(kù)都拷貝過(guò)來(lái)
4. 安裝包制作,首先下載Inno Setup官方鏈接
5.新建腳本模式
6.修改程序信息
7.設(shè)置打包程序位置
8.添加原始exe和文件夾路徑
9.下面這個(gè)關(guān)聯(lián)格式的不要點(diǎn)
10.創(chuàng)建快捷方式(無(wú)需修改)
11.設(shè)置安裝向?qū)?無(wú)需修改)
12.選擇安全模式(無(wú)需修改)
13.語(yǔ)言選擇(無(wú)需修改,沒(méi)得中文)
14.設(shè)置安裝文件的相關(guān)信息(生成的exe位置、名稱、圖標(biāo)和安裝時(shí)的密碼)
后面的一路ok就好了就可以打開(kāi)了
#五、第一個(gè)項(xiàng)目(攝像頭播放)
要用到opencv調(diào)攝像頭,所以把opencv也配置到vs中:
1.在”VC++目錄"→“包含目錄”中增加opencv\bulid的include和include中的opencv2路徑
2.在"庫(kù)目錄"中增加opencv\build\x64\vc15\lib路徑
3.在"鏈接器"→"輸入"→"附加依賴項(xiàng)"中增加opencv_worldxxx_lib(如果配置為Debug,選擇opencv_worldxxxd.lib
如果為Release,選擇opencv_worldxxx.lib)
1.原代碼(已改過(guò)命名方式)
ui
/********************************************************************************
** Form generated from reading UI file 'QT_learning1.ui'
**
** Created by: Qt User Interface Compiler version 5.14.2
**
** WARNING! All changes made in this file will be lost when recompiling UI file!
********************************************************************************/
#ifndef UI_QT_LEARNING1_H
#define UI_QT_LEARNING1_H
#include <QtCore/QVariant>
#include <QtWidgets/QApplication>
#include <QtWidgets/QLabel>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QWidget>
QT_BEGIN_NAMESPACE
class Ui_QT_learning1Class
{
public:
QPushButton *Open_Camera;
QPushButton *Capture;
QPushButton *Close_Camera;
QLabel *Video;
QLabel *Photo;
QLabel *label;
QLabel *label_2;
void setupUi(QWidget *QT_learning1Class)
{
if (QT_learning1Class->objectName().isEmpty())
QT_learning1Class->setObjectName(QString::fromUtf8("QT_learning1Class"));
QT_learning1Class->resize(600, 400);
Open_Camera = new QPushButton(QT_learning1Class);
Open_Camera->setObjectName(QString::fromUtf8("Open_Camera"));
Open_Camera->setGeometry(QRect(100, 330, 93, 28));
Capture = new QPushButton(QT_learning1Class);
Capture->setObjectName(QString::fromUtf8("Capture"));
Capture->setGeometry(QRect(250, 330, 93, 28));
Close_Camera = new QPushButton(QT_learning1Class);
Close_Camera->setObjectName(QString::fromUtf8("Close_Camera"));
Close_Camera->setGeometry(QRect(400, 330, 93, 28));
Video = new QLabel(QT_learning1Class);
Video->setObjectName(QString::fromUtf8("Video"));
Video->setGeometry(QRect(40, 40, 224, 224));
Photo = new QLabel(QT_learning1Class);
Photo->setObjectName(QString::fromUtf8("Photo"));
Photo->setGeometry(QRect(310, 40, 224, 224));
label = new QLabel(QT_learning1Class);
label->setObjectName(QString::fromUtf8("label"));
label->setGeometry(QRect(110, 280, 81, 16));
label_2 = new QLabel(QT_learning1Class);
label_2->setObjectName(QString::fromUtf8("label_2"));
label_2->setGeometry(QRect(410, 280, 72, 15));
retranslateUi(QT_learning1Class);
QMetaObject::connectSlotsByName(QT_learning1Class);
} // setupUi
void retranslateUi(QWidget *QT_learning1Class)
{
QT_learning1Class->setWindowTitle(QCoreApplication::translate("QT_learning1Class", "QT_learning1", nullptr));
Open_Camera->setText(QCoreApplication::translate("QT_learning1Class", "\346\211\223\345\274\200\346\221\204\345\203\217\345\244\264", nullptr));
Capture->setText(QCoreApplication::translate("QT_learning1Class", "\346\213\215\347\205\247", nullptr));
Close_Camera->setText(QCoreApplication::translate("QT_learning1Class", "\345\205\263\351\227\255\346\221\204\345\203\217\345\244\264", nullptr));
Video->setText(QString());
Photo->setText(QString());
label->setText(QCoreApplication::translate("QT_learning1Class", "\346\221\204\345\203\217\345\244\264\351\242\204\350\247\210", nullptr));
label_2->setText(QCoreApplication::translate("QT_learning1Class", "\347\205\247\347\211\207", nullptr));
} // retranslateUi
};
namespace Ui {
class QT_learning1Class: public Ui_QT_learning1Class {};
} // namespace Ui
QT_END_NAMESPACE
#endif // UI_QT_LEARNING1_H
h文件
#pragma once
#include <QtWidgets/QWidget>
#include "ui_QT_learning1.h"
#ifndef QT_LEARNING1_H
#define QT_LEARNING1_H
#include <opencv2\core\core.hpp>
#include <QWidget>
#include <QImage>
#include <QTimer> // 設(shè)置采集數(shù)據(jù)的間隔時(shí)間
#include <QGraphicsScene>
#include <QGraphicsView>
#include <highgui/highgui_c.h> //包含opencv庫(kù)頭文件
#include <opencv2\imgproc\imgproc.hpp>
#include <opencv2\core\core.hpp>
#include <opencv2\highgui\highgui.hpp> //opencv申明
#include <opencv.hpp>
using namespace cv;
namespace Ui {
class QT_learning1;
}
class QT_learning1 : public QWidget
{
Q_OBJECT
public:
explicit QT_learning1(QWidget *parent = 0);
~QT_learning1();
private slots:
void openCamara(); // 打開(kāi)攝像頭
void getFrame(); // 讀取當(dāng)前幀信息
void closeCamara(); // 關(guān)閉攝像頭。
void takingPictures(); // 拍照
private:
Ui::QT_learning1Class ui;
QTimer *timer;
QImage *imag;
CvCapture *cam;// 視頻獲取結(jié)構(gòu), 用來(lái)作為視頻獲取函數(shù)的一個(gè)參數(shù)
IplImage *frame;
VideoCapture capture1;
Mat showimage;
QImage Mat2Qimage(Mat cvImg);
//QT_learning1(QWidget * parent);
//申請(qǐng)IplImage類(lèi)型指針,就是申請(qǐng)內(nèi)存空間來(lái)存放每一幀圖像
};
#endif // QT_LEARNING1_H
cpp文件
(攝像頭找不到得話,將capture1.open(0)中的0改成1或者-1試試)
#include "QT_learning1.h"
#include<stdlib.h>
#include <ctime>
#include<random>
#include<opencv.hpp>
using namespace cv;
using namespace std;
QT_learning1::QT_learning1(QWidget *parent) :
QWidget(parent)
{
ui.setupUi(this);
connect(ui.Open_Camera, SIGNAL(clicked()), this, SLOT(openCamara()));
connect(ui.Capture, SIGNAL(clicked()), this, SLOT(takingPictures()));
connect(ui.Close_Camera, SIGNAL(clicked()), this, SLOT(closeCamara()));
setWindowTitle(tr("Main Window"));
timer = new QTimer(this);
imag = new QImage();
connect(timer, SIGNAL(timeout()), this, SLOT(getFrame()));//超時(shí)就讀取當(dāng)前攝像頭信息
}
QT_learning1::~QT_learning1()
{
}
void QT_learning1::openCamara()
{
capture1.open(0); //打開(kāi)攝像頭,從攝像頭中獲取視頻
timer->start(10);
}
void QT_learning1::getFrame() {
capture1 >> showimage;
QImage imag = Mat2Qimage(showimage);
ui.Video->setScaledContents(true);
ui.Video->setPixmap(QPixmap::fromImage(imag));
}
void QT_learning1::closeCamara()
{
timer->stop();
ui.Video->clear();
capture1.release();
}
void QT_learning1::takingPictures()
{
capture1.open(0);
capture1 >> showimage;
QImage img = Mat2Qimage(showimage);
ui.Photo->setScaledContents(true);
ui.Photo->setPixmap(QPixmap::fromImage(img));
string writePath = "./";
string name;
time_t now = time(0);
name = writePath + to_string(now) + ".jpg";
imwrite(name, showimage);
}
QImage QT_learning1::Mat2Qimage(Mat cvImg)
{
// 8-bits unsigned, NO. OF CHANNELS = 1
if (cvImg.type() == CV_8UC1)
{
QImage image(cvImg.cols, cvImg.rows, QImage::Format_Indexed8);
// Set the color table (used to translate colour indexes to qRgb values)
image.setColorCount(256);
for (int i = 0; i < 256; i++)
{
image.setColor(i, qRgb(i, i, i));
}
// Copy input Mat
uchar *pSrc = cvImg.data;
for (int row = 0; row < cvImg.rows; row++)
{
uchar *pDest = image.scanLine(row);
memcpy(pDest, pSrc, cvImg.cols);
pSrc += cvImg.step;
}
return image;
}
// 8-bits unsigned, NO. OF CHANNELS = 3
else if (cvImg.type() == CV_8UC3)
{
// Copy input Mat
const uchar *pSrc = (const uchar*)cvImg.data;
// Create QImage with same dimensions as input Mat
QImage image(pSrc, cvImg.cols, cvImg.rows, cvImg.step, QImage::Format_RGB888);
return image.rgbSwapped();
}
else if (cvImg.type() == CV_8UC4)
{
// qDebug() << "CV_8UC4";
// Copy input Mat
const uchar *pSrc = (const uchar*)cvImg.data;
// Create QImage with same dimensions as input Mat
QImage image(pSrc, cvImg.cols, cvImg.rows, cvImg.step, QImage::Format_ARGB32);
return image.copy();
}
else
{
// qDebug() << "ERROR: Mat could not be converted to QImage.";
return QImage();
}
}
main.cpp
#include "QT_learning1.h"
#include <QtWidgets/QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QT_learning1 w;
w.show();
return a.exec();
}
效果
還行,但有兩個(gè)問(wèn)題:
1.拍照得到的照片失真,原因是打開(kāi)攝像頭和拍照重復(fù)使用攝像頭接口,導(dǎo)致數(shù)據(jù)傳輸變慢、沖突
2.沒(méi)有多線程,如果再來(lái)個(gè)功能或者運(yùn)算量變大就over了
2.把cpp文件替換為下面得即可解決第一個(gè)問(wèn)題
#include "QT_learning1.h"
#include<stdlib.h>
#include <thread>
#include <ctime>
#include<random>
#include<opencv.hpp>
using namespace cv;
using namespace std;
QT_learning1::QT_learning1(QWidget *parent) :
QWidget(parent)
{
ui.setupUi(this);
connect(ui.Open_Camera, SIGNAL(clicked()), this, SLOT(openCamara()));
connect(ui.Capture, SIGNAL(clicked()), this, SLOT(takingPictures()));
connect(ui.Close_Camera, SIGNAL(clicked()), this, SLOT(closeCamara()));
setWindowTitle(tr("Main Window"));
timer = new QTimer(this);
imag = new QImage();
connect(timer, SIGNAL(timeout()), this, SLOT(getFrame()));//超時(shí)就讀取當(dāng)前攝像頭信息
}
QT_learning1::~QT_learning1()
{
}
void QT_learning1::openCamara()
{
capture1.open(0); //打開(kāi)攝像頭,從攝像頭中獲取視頻
timer->start(10);
}
void QT_learning1::getFrame() {
capture1 >> showimage;
QImage imag = Mat2Qimage(showimage);
ui.Video->setScaledContents(true);
ui.Video->setPixmap(QPixmap::fromImage(imag));
}
void QT_learning1::closeCamara()
{
timer->stop();
ui.Video->clear();
capture1.release();
}
void QT_learning1::takingPictures()
{
QImage img = Mat2Qimage(showimage);
ui.Photo->setScaledContents(true);
ui.Photo->setPixmap(QPixmap::fromImage(img));
string writePath = "./";
string name;
time_t now = time(0);
name = writePath + to_string(now) + ".jpg";
imwrite(name, showimage);
}
QImage QT_learning1::Mat2Qimage(Mat cvImg)
{
// 8-bits unsigned, NO. OF CHANNELS = 1
if (cvImg.type() == CV_8UC1)
{
QImage image(cvImg.cols, cvImg.rows, QImage::Format_Indexed8);
// Set the color table (used to translate colour indexes to qRgb values)
image.setColorCount(256);
for (int i = 0; i < 256; i++)
{
image.setColor(i, qRgb(i, i, i));
}
// Copy input Mat
uchar *pSrc = cvImg.data;
for (int row = 0; row < cvImg.rows; row++)
{
uchar *pDest = image.scanLine(row);
memcpy(pDest, pSrc, cvImg.cols);
pSrc += cvImg.step;
}
return image;
}
// 8-bits unsigned, NO. OF CHANNELS = 3
else if (cvImg.type() == CV_8UC3)
{
// Copy input Mat
const uchar *pSrc = (const uchar*)cvImg.data;
// Create QImage with same dimensions as input Mat
QImage image(pSrc, cvImg.cols, cvImg.rows, cvImg.step, QImage::Format_RGB888);
return image.rgbSwapped();
}
else if (cvImg.type() == CV_8UC4)
{
// qDebug() << "CV_8UC4";
// Copy input Mat
const uchar *pSrc = (const uchar*)cvImg.data;
// Create QImage with same dimensions as input Mat
QImage image(pSrc, cvImg.cols, cvImg.rows, cvImg.step, QImage::Format_ARGB32);
return image.copy();
}
else
{
// qDebug() << "ERROR: Mat could not be converted to QImage.";
return QImage();
}
}
這樣就ok了
3.多線程
C++中可直接使用thread庫(kù)實(shí)現(xiàn)
而QT提供了兩種方式實(shí)現(xiàn)多線程:
1.繼承QThread的run函數(shù),是個(gè)虛函數(shù),會(huì)自動(dòng)調(diào)用的
2.繼承于QObject的類(lèi)用moveToThread函數(shù)轉(zhuǎn)移到一個(gè)Thread里
第一種QThread已經(jīng)不推薦了,我們使用QObject實(shí)現(xiàn)
1.QObject實(shí)現(xiàn)思路
1.創(chuàng)鍵一個(gè)繼承于 QObject 的自定義線程類(lèi)(如:MyThread),用來(lái)盛放比較耗時(shí),需要放入子線程的處理函數(shù)
(1)定義一個(gè)線程處理函數(shù)(如:MyWork),當(dāng)然也可以定義多個(gè),這時(shí)多個(gè)處理函數(shù)就共用一個(gè)子線程
(2)在處理函數(shù)中進(jìn)行處理,此過(guò)程可能時(shí)間較長(zhǎng)(如:QThread::sleep(1))
(3)在處理函數(shù)中發(fā)送處理完成的信號(hào)(如:emit signal_back()),當(dāng)然該信號(hào)中可能含有處理的結(jié)果信息(如計(jì)算結(jié)果)
2、 在主線程(亦稱界面線程)中創(chuàng)建一個(gè)子線程(QThread* subthread = new QThread(this))
3、新建一個(gè)自定義線程類(lèi)對(duì)象(MyThread* m_MyThread = new MyThread())
4、將自定義線程類(lèi)對(duì)象移入子線程容器中(m_MyThread->moveToThread(subthread)),其實(shí)也可以移入多個(gè)自定義線程類(lèi)到同一個(gè)subthread中,這時(shí)他們就共享一個(gè)子線程了
5、連接主線程和子線程之間的信號(hào)和槽
(1)主線程——>子線程,主線程的信號(hào)和子線程的槽
connect ( this, &MainWindow::StartThread, m_MyThread, &MyThread::MyWork )
(2)子線程——>主線程,子線程的信號(hào)和主線程的槽
connect (m_MyThread, &MyThread::signal_back, this, &MainWindow::slot_handle_finish )
6、子線程使用完畢需要回收銷(xiāo)毀,不然該線程會(huì)一直占用,而系統(tǒng)可分配的線程數(shù)量是有限的
(1)subthread->qiut(); //該停止函數(shù)比較弱,會(huì)等到線程處理函數(shù)MyWork()的任務(wù)執(zhí)行完之后,才會(huì)停止線程
(2)subthread->wait();文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-471168.html
所有通常會(huì)加入一個(gè)標(biāo)志位,來(lái)終止任務(wù)。
未完待續(xù)。。。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-471168.html
到了這里,關(guān)于【使用VS開(kāi)發(fā)的第一個(gè)QT項(xiàng)目——實(shí)現(xiàn)相機(jī)功能(包括QT下載、配置、攝像頭程序)】的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!