3. PC程式
為了配合Arduino能正確依排程設定顯示指定的圖框影像及文字橫幅,所以必須在PC端開發一套影像轉檔及下載程式。本專案在這裡選用Windows環境加上QT 5.6版(方便跨平台)及OpenCV 3.2版來進行開發視窗程式。QT及OpenCV的版本原則上不太重要,較舊的版本應該也可以,因為並沒有用到太多功能。目前這版程式離真正的電子看板排程程式還差得滿遠的,但作為展示、學習用,還是相當合適的。為了簡化程式開發,本專案只提供三組圖框影像及三組橫幅文字設定。如圖八所示,可依下列步驟操作。
1. 載入所需圖框影像,若影像大於220*176則會自動縮小(不論原圖長寬比例)。
2. 設定顯示停留時間,單位為0.1秒。
3. 再來輸入文字內容,這裡支援任何文字輸入(中英文混合亦可)
4. 按[C]鍵指定文字及背景色,亦可按[字體]鍵選定指定字體及尺寸。
5. 指定橫幅文字顯示模式,固定顯示、交替閃爍及不顯示。
完成三組圖框影像及橫幅文字設定後就可準備下載工作了。
一般來說在電腦上的彩色影像是全彩(紅、綠、藍各以8bit表示,俗稱RGB888),但這裡我們利用OpenCV讀取影像檔案時,它會變成BGR888(24bit),紅綠通道會相反,而LCD顯示時因為只用了16bit,所以需降低色彩數變成RGB565,明顯可看出色彩數量及表示方式有很大差異。因此影像要下載到Arduino前必須進行格式轉換,不然無法正確顯示在LCD上。詳細作法可參見ColorBGR8882RGB565函式。
圖八、載入圖框影像、設定排程、編輯橫幅文字及設定顯示模式 |
要下載資料前,首先按下Arduino Pro Mini的重置鍵,讓系統回到等待下載模式。接著用USB轉UART轉接板連接Arduino Pro Mini和PC端。接下來就如圖九所示,按下【檢查】鍵確認USB轉UART轉接板是否已啟動,若正常工作時,會出現埠名(COM)及描述,此時【開啟通訊埠】鍵也會被致能,按下後就會開啟通訊埠準備輸出資料到Arduino Pro Mini。此時若想試一下是否通訊正常,可按【LED On】和【LED Off】來點亮及熄滅板子上的LED。再來按下【下載】鍵,等個約五十秒就可下載完所有資料。
目前傳輸時間看起來有點久,主要是因為通訊埠(COM)通訊鮑率設定只有57,600bps。因為不知那個地方產生干擾,導致設為115,200bps時會接收到亂碼,希望後續找到問題並解決後,下載速度就可大幅提升。若要再更快那可能就換掉Arduino,改用具有USB大量傳輸(Bluk)能力MCU才能徹底改善。
圖九、通訊埠檢查、開啟及排程、圖像下載 |
完整程式碼及註解如下所示,或可直接到https://github.com/OmniXRI/OpenQSignage下載。
// *********** OpenQSignageConverter.pro ******************
#-------------------------------------------------
#
# Project created by QtCreator 2018-01-09T14:38:59
#
#-------------------------------------------------
QT += core gui
QT += widgets serialport
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = OpenQSignageConverter
TEMPLATE = app
CONFIG += qt warn_on release
LIBS += -L C:\OpenCV-3.2.0\mingw\install\x86\mingw\lib\libopencv_*.a
INCLUDEPATH += C:\OpenCV-3.2.0\mingw\install\include\
C:\OpenCV-3.2.0\mingw\install\include\opencv
C:\OpenCV-3.2.0\mingw\install\include\opencv2
SOURCES += main.cpp\
mainwindow.cpp
HEADERS += mainwindow.h
FORMS += mainwindow.ui
// *********** main.cpp ******************
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
// *********** mainwindow.h ******************
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QFileDialog>
#include <QLabel>
#include <QMessageBox>
#include <qevent.h>
#include <QCoreApplication>
#include <QPainter>
#include <QFontDialog>
#include <QColorDialog>
#include <QtSerialPort/QSerialPort>
#include <QtSerialPort/QSerialPortInfo>
#include <time.h>
#include <opencv2/opencv.hpp>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
protected:
private slots:
void on_btnDownload_clicked();
void on_btnPortOpen_clicked();
void on_btnPortClose_clicked();
void on_btnCheckComPort_clicked();
void on_btnLoadF1_clicked();
void on_btnLoadF2_clicked();
void on_btnLoadF3_clicked();
void on_btnLED0_clicked();
void on_btnLED1_clicked();
void on_btnGoB1_clicked();
void on_btnFontB1_clicked();
void on_btnBGColorB1_clicked();
void on_btnFGColorB1_clicked();
void on_btnBGColorB2_clicked();
void on_btnFGColorB2_clicked();
void on_btnBGColorB3_clicked();
void on_btnFGColorB3_clicked();
void on_btnGoB2_clicked();
void on_btnFontB2_clicked();
void on_btnGoB3_clicked();
void on_btnFontB3_clicked();
void on_spbF1_valueChanged(double arg1);
void on_spbF2_valueChanged(double arg1);
void on_spbF3_valueChanged(double arg1);
void on_rdbFixB1_clicked();
void on_rdbBlinkB1_clicked();
void on_rdbNoneB1_clicked();
void on_rdbFixB2_clicked();
void on_rdbBlinkB2_clicked();
void on_rdbNoneB2_clicked();
void on_rdbFixB3_clicked();
void on_rdbBlinkB3_clicked();
void on_rdbNoneB3_clicked();
private:
void SetLabelColor(QLabel *lab, QColor bg_color);
void ShowFrame(cv::Mat imgS, QLabel *imgT);
void ColorBGR8882RGB565(cv::Mat &imgSrc, cv::Mat &imgTrg);
Ui::MainWindow *ui;
QSerialPort *myport; // UART通訊埠
QString fileName; // 載入影像之檔名
cv::Mat imgSrc1; // 原始影像(BGR888)
cv::Mat imgSrc2;
cv::Mat imgSrc3;
cv::Mat imgF1; // 原始影像縮小後之圖框影像(BGR888)
cv::Mat imgF2;
cv::Mat imgF3;
cv::Mat imgB1; // 橫幅原始影像(BGR888)
cv::Mat imgB2;
cv::Mat imgB3;
cv::Mat imgLCDF1; // LCD用圖框影像(RGB565)
cv::Mat imgLCDF2;
cv::Mat imgLCDF3;
cv::Mat imgLCDB1; // LCD用橫幅影像(RGB565)
cv::Mat imgLCDB2;
cv::Mat imgLCDB3;
QFont fontB1; // 橫幅字體
QFont fontB2;
QFont fontB3;
QColor BGColorB1; // 橫幅背景色
QColor BGColorB2;
QColor BGColorB3;
QColor FGColorB1; // 橫幅前景(文字)色
QColor FGColorB2;
QColor FGColorB3;
int disp_timerF1; // 顯示停留時間
int disp_timerB1;
int disp_timerF2;
int disp_timerB2;
int disp_timerF3;
int disp_timerB3;
int disp_modeF1; // 圖框顯示模式
int disp_modeB1; // 橫幅顯示模式
int disp_modeF2;
int disp_modeB2;
int disp_modeF3;
int disp_modeB3;
};
#endif // MAINWINDOW_H
// *********** mainwindow.cpp ******************
#include "mainwindow.h"
#include "ui_mainwindow.h"
using namespace std;
using namespace cv;
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
qApp->installEventFilter(this);
ui->pbxF1->setScaledContents(true); // 影像自動縮放至Label尺寸
ui->pbxF2->setScaledContents(true); // 影像自動縮放至Label尺寸
ui->pbxF3->setScaledContents(true); // 影像自動縮放至Label尺寸
fontB1 = fontB2 = fontB3 = QFont("Times", 14, QFont::Bold); // 橫幅字體預設值為Times 14 粗體字
BGColorB1 = BGColorB2 = BGColorB3 = Qt::white; // 橫幅背景色預設為白色
FGColorB1 = FGColorB2 = FGColorB3 = Qt::black; // 橫幅前景(文字)色預設為黑色
SetLabelColor(ui->labBGColorB1, Qt::white); SetLabelColor(ui->labFGColorB1, Qt::black); // 預設橫幅一標籤為白底黑字
SetLabelColor(ui->labBGColorB2, Qt::white); SetLabelColor(ui->labFGColorB2, Qt::black); // 預設橫幅二標籤為白底黑字
SetLabelColor(ui->labBGColorB3, Qt::white); SetLabelColor(ui->labFGColorB3, Qt::black); // 預設橫幅三標籤為白底黑字
disp_timerF1 = disp_timerF2 = disp_timerF3 = disp_timerB1 = disp_timerB2 = disp_timerB3 = 30; // 預設排程停留時間3.0 sec
disp_modeF1 = disp_modeF2 = disp_modeF3 = disp_modeB1 = disp_modeB2 = disp_modeB3 = 0; // 預設顯示模式皆為固定顯示模式
}
MainWindow::~MainWindow()
{
if(myport->isOpen()) // 若COM埠還開著
myport->close(); // 就關閉
delete ui;
}
// 將cv::Mat BGR888轉換為RGB888再顯示在QLabel上
// imgS 輸入影像
// imgT 輸出標籤
void MainWindow::ShowFrame(cv::Mat imgS, QLabel *imgT)
{
Mat imgC;
cvtColor(imgS,imgC,cv::COLOR_BGR2RGB); // 轉換色彩由BGR888到RGB888
QImage tmp(imgC.data,
imgC.cols,
imgC.rows,
//imgC.step,
QImage::Format_RGB888);
imgT->setPixmap(QPixmap::fromImage(tmp)); // 設定QImage影像到QLabel
}
// 設定標籤背景及文字顏色(色彩反相)
void MainWindow::SetLabelColor(QLabel *lab, QColor bg_color)
{
QPalette palette;
QColor fg_color;
int r,g,b;
bg_color.getRgb(&r,&g,&b); // 取得標籤目前背景顏色
fg_color = QColor(255-r,255-g,255-b); // 產生標籤前景(文色)反相顏色
palette = lab->palette(); // 為標籤指定色盤
palette.setColor(lab->backgroundRole(), bg_color); // 設定色盤背景色
palette.setColor(lab->foregroundRole(), fg_color); // 設定色盤前景色
lab->setAutoFillBackground(true); // 設定自動填滿背景色(一定要設)
lab->setPalette(palette); // 設定調色盤,變更標籤前背景色
}
// 將來源影像cv::Mat(BGR888)轉成LCD顯示用影像(RGB565)
// imrSrc: BGR888_24bit:[B7][B6][B5][B4][B3][B2][B1][B0]
// (CV_8UC3) [G7][G6][G5][G4][G3][G2][G1][G0]
// [R7][R6][R5][R4][R3][R2][R1][R0]
// imgTrg: RGB565_16bit:[R7][R6][R5][R4][R3][G7][G6][G5]
// (CV_8UC2) [G4][G3][G2][B7][B6][B5][B4][B3]
void MainWindow::ColorBGR8882RGB565(Mat &imgSrc, Mat &imgTrg)
{
unsigned char *ptrS;
unsigned char *ptrT;
int posS, posT;
if((imgSrc.cols != imgTrg.cols) || (imgSrc.rows != imgTrg.rows)){ // 確認輸入和輸出影像尺寸要相符
QMessageBox::critical(this,"Error","Image size different!");
return;
}
for(int i=0; i<imgSrc.rows; i++){ // 設定迴圈數為影像高度
ptrS = imgSrc.ptr<unsigned char>(i); // 取得來源影像第i列(row)起始位置指標
ptrT = imgTrg.ptr<unsigned char>(i); // 取得目標影像第i列(row)起始位置指標
for(int j=0,posS=0,posT=0; j<imgSrc.cols; j++,posS+=3, posT+=2){
ptrT[posT] = (ptrS[posS+2] & 0xF8) | (ptrS[posS+1] >> 5); // RGB565高位元組(R5+G3)
ptrT[posT+1] = ((ptrS[posS+1] & 0x1C) << 3) | (ptrS[posS] >> 3); // RGB565低位元組(G3+B5)
}
}
}
// 以UART傳送點亮LED命令
void MainWindow::on_btnLED1_clicked()
{
char cmd = 0xA5; // 點亮LED命令
myport->write(&cmd); // 透過UART送出命令
}
// 以UART傳送熄滅LED命令
void MainWindow::on_btnLED0_clicked()
{
char cmd = 0xB4; // 熄滅LED命令
myport->write(&cmd); // 透過UART送出命令
}
// 以UART將圖框排程及影像內容傳送到Arduino
void MainWindow::on_btnDownload_clicked()
{
double t0, t1, t2;
QString str;
vector<cv::Mat> vecS;
vector<cv::Mat> vecT;
int total_frame;
int frame_w = ui->txbFrameW->text().toInt(); // 取得圖框寬度
int frame_h = ui->txbFrameH->text().toInt(); // 取得圖框高度
int d_mode[6] = {disp_modeF1, disp_modeB1, disp_modeF2, disp_modeB2, disp_modeF3, disp_modeB3}; // 圖框(橫幅)顯示模式
int d_timer[6] = {disp_timerF1, disp_timerB1, disp_timerF2, disp_timerB2, disp_timerF3, disp_timerB3}; // 圖框(橫幅)顯示停留時間
t0 = (double)clock(); // 啟動計時器
str = "display mode = ";
for(int i=0; i<6; i++){
str += (QString::number(d_mode[i]) + ", ");
}
ui->txbRxData->append(str); // 將待傳送「顯示模式」內容顯示在狀態框
str = "dwell time = ";
for(int i=0; i<6; i++){
str += (QString::number(d_timer[i]) + ", ");
}
ui->txbRxData->append(str); // 將待傳送「停留時間」內容顯示在狀態框
cv::resize(imgSrc1,imgF1,imgF1.size()); // 重新取得圖框內容並縮放到LCD尺寸(像素)
cv::resize(imgSrc2,imgF2,imgF2.size()); // 避免橫幅蓋掉圖框
cv::resize(imgSrc3,imgF3,imgF3.size());
vecS.push_back(imgF1); // 將圖框(橫幅)推入影像陣列vecS
vecS.push_back(imgB1);
vecS.push_back(imgF2);
vecS.push_back(imgB2);
vecS.push_back(imgF3);
vecS.push_back(imgB3);
vecT.push_back(imgLCDF1); // 將LCD轉換結果影像推入影像陣列vecT
vecT.push_back(imgLCDB1);
vecT.push_back(imgLCDF2);
vecT.push_back(imgLCDB2);
vecT.push_back(imgLCDF3);
vecT.push_back(imgLCDB3);
total_frame = vecT.size(); // 取得圖框(橫幅)數量
t1 = (double)clock(); // 取得時間1
// 計算所有傳輸資料量(位元組)
long total_size = (imgF1.cols * imgF1.rows * 2 * (total_frame/2)) + (imgB1.cols * imgB1.rows * 2 * (total_frame/2));
long curr_size = 0; // 目前已傳輸資料量(位元組)
char cmd = 0xC3; // UART開始傳送資料命令
char ack; // Arduino回應
myport->clear(); // 清除通訊埠(COM)
myport->write(&cmd); // 透過UART送出命令
for(int f=0; f<total_frame; f++){ // 迴圈設為欲傳送之圖框數量
char frame_format[10]; // 配置圖框排程資料區
frame_format[0] = vecT[f].cols >> 8; // 圖框(橫幅)寬度高位元組
frame_format[1] = vecT[f].cols & 0x00ff; // 圖框(橫幅)寬度低位元組
frame_format[2] = vecT[f].rows >> 8; // 圖框(橫幅)高度高位元組
frame_format[3] = vecT[f].rows & 0x00ff; // 圖框(橫幅)高度低位元組
frame_format[4] = (frame_w - vecT[f].cols) >> 8; // 顯示起始位置sx高位元組
frame_format[5] = (frame_w - vecT[f].cols) & 0x00ff; // 顯示起始位置sx低位元組
frame_format[6] = (frame_h - vecT[f].rows) >> 8; // 顯示起始位置sy高位元組
frame_format[7] = (frame_h - vecT[f].rows) & 0x00ff; // 顯示起始位置sy低位元組
frame_format[8] = d_mode[f]; // 顯示模式, 0:固定顯示, 1:交替閃爍, 2:不顯示
frame_format[9] = d_timer[f]; // 顯示停留時間,0.0 ~ 25.5 sec轉換成 0 ~ 255
myport->write(frame_format, 10); // 透過UART寫入10位元組
ack = 0; // 清除回應值
if(myport->waitForReadyRead(3000)){ // 等待回應(最多等3秒)
myport->read(&ack,1); // 取得回應值
}
char *ptrS;
ColorBGR8882RGB565(vecS[f], vecT[f]); // 轉換RGB888成為RGB565
for(int i=0; i<vecT[f].rows; i++){ // 設定迴圈數量為影像高度
ptrS = vecT[f].ptr<char>(i); // 取得LCD影像第i列(row)起始位置指標
myport->write(ptrS,vecT[f].cols*2); // 一次送出一列資料 (最大不可超過1K位元組)
ack = 0; // 清除回應值
if(myport->waitForReadyRead(3000)){ // 等待回應(最多等3秒)
myport->read(&ack,1); // 取得回應值
}
curr_size += (vecT[f].cols*2); // 目前傳送值加上影像寬度*2
ui->pgbDownload->setValue(((i+1)/(vecT[f].rows*1.0))*100); // 計算單張影像傳送百分比
ui->pgbDownload->update(); // 更新單張影像下載進度條
ui->pgbTotal->setValue((curr_size/(total_size*1.0))*100); // 計算所有影像傳送百分比
ui->pgbTotal->update(); // 更新所有影像下載進度條
}
}
t2 = (double)clock(); // 取得目前時間
str = "Image convert time = " + QString::number((t1-t0)/1000.0,'f',3) + "second."; // 計算影像轉換時間
ui->txbRxData->append(str); // 顯示於狀態框
str = "Image download time = " + QString::number((t2-t1)/1000.0,'f',3) + "second."; // 計算影像下載時間
ui->txbRxData->append(str); // 顯示於狀態框
ui->txbRxData->append("Transfer done!"); // 顯示完成訊息於狀態框
QMessageBox::information(this,tr("訊息"),tr("圖像下載完成!")); // 顯示完成訊息盒
}
// 檢查系統COM數量
void MainWindow::on_btnCheckComPort_clicked()
{
// 取得所有可用的COM埠名稱表列
QList<QSerialPortInfo> serialPortInfoList = QSerialPortInfo::availablePorts();
if(serialPortInfoList.size() == 0) // 若找不到任何COM埠
ui->txbRxData->append("No find COM Port!"); // 在狀態框顯示找不到訊息
else{ // 若有找到COM埠
for (int i = 0; i < serialPortInfoList.size(); i++) { // 設定迴圈數為COM埠數量
ui->txbPortName->setText(serialPortInfoList.at(i).portName()); // 將COM埠名稱顯示於文字盒
ui->txbPortDescription->setText(serialPortInfoList.at(i).description()); // 將COM埠描述顯示於文字盒
}
ui->btnPortOpen->setEnabled(true); // 致能[開啟通訊埠]按鍵
}
}
// 開啟通訊埠
void MainWindow::on_btnPortOpen_clicked()
{
myport = new QSerialPort(ui->txbPortName->text()); // 依檢查到的埠名開啟COM埠
myport->setBaudRate(QSerialPort::Baud57600); // 設定通訊鮑率 57,600bps
myport->setDataBits(QSerialPort::Data8); // 設定傳輸字元為8位元
myport->setParity(QSerialPort::NoParity); // 設定為無同位元
myport->setStopBits(QSerialPort::OneStop); // 設定停止位元為1
myport->setFlowControl(QSerialPort::NoFlowControl); // 設定無流量控制
if (!myport->open(QIODevice::ReadWrite)){ // 若COM埠開啟失敗
ui->txbRxData->append("serial port open failed"); // 顯示訊息於狀態框
ui->btnPortOpen->setEnabled(false); // 禁能[開啟通訊埠]按鍵
ui->btnPortClose->setEnabled(false); // 禁能[關閉通訊埠]按鍵
ui->btnLED0->setEnabled(false); // 禁能[LED Off]按鍵
ui->btnLED1->setEnabled(false); // 禁能[LED On]按鍵
ui->btnDownload->setEnabled(false); // 禁能[下載」按鍵
}
else{ // 若COM埠開啟成功
ui->txbRxData->append("serial port open sucessed"); // 顯示訊息於狀態框
ui->btnPortOpen->setEnabled(false); // 禁能[開啟通訊埠]按鍵(不可重覆開啟)
ui->btnPortClose->setEnabled(true); // 致能[關閉通訊埠]按鍵
ui->btnLED0->setEnabled(true); // 致能[LED Off]按鍵
ui->btnLED1->setEnabled(true); // 致能[LED On]按鍵
ui->btnDownload->setEnabled(true); // 致能[下載」按鍵
}
}
// 關閉通訊埠
void MainWindow::on_btnPortClose_clicked()
{
if(myport->isOpen()){ // 若通訊埠已開啟
myport->close(); // 關閉通訊埠
ui->txbRxData->append("serial port close sucessed"); // 顯示訊息於狀態框
ui->btnPortOpen->setEnabled(true); // 致能[開啟通訊埠]按鍵
ui->btnPortClose->setEnabled(false); // 禁能[關閉通訊埠]按鍵
ui->btnLED0->setEnabled(false); // 禁能[LED Off]按鍵
ui->btnLED1->setEnabled(false); // 禁能[LED On]按鍵
ui->btnDownload->setEnabled(false); // 禁能[下載」按鍵
}
}
// 載入圖框影像一
void MainWindow::on_btnLoadF1_clicked()
{
fileName = QFileDialog::getOpenFileName(this,tr("Open File")); // 開啟檔案對話盒並取得檔名
imgSrc1 = cv::imread(fileName.toStdString(),IMREAD_COLOR); // 讀入影像
if(!imgSrc1.empty()) { // 若影像不空
int fw = ui->txbFrameW->text().toInt(); // 取得圖框寬度
int fh = ui->txbFrameH->text().toInt(); // 取得圖框高度
int bw = ui->txbBannerW->text().toInt(); // 取得橫幅寬度
int bh = ui->txbBannerH->text().toInt(); // 取得橫幅高度
cv::resize(imgSrc1,imgF1,cvSize(fw,fh)); // 將原始影像縮到指定圖框尺寸
imgLCDF1 = Mat::zeros(cv::Size(fw,fh),CV_8UC2); // 清除圖框影像緩衝區
imgLCDB1 = Mat::zeros(cv::Size(bw,bh),CV_8UC2); // 清除橫幅影像緩衝區
ShowFrame(imgF1, ui->pbxF1); // 將圖框影像秀在標籤上
ui->btnGoB1->setEnabled(true); // 致能[更新]按鍵
}
}
// 載入圖框影像二
void MainWindow::on_btnLoadF2_clicked()
{
fileName = QFileDialog::getOpenFileName(this,tr("Open File")); // 開啟檔案對話盒並取得檔名
imgSrc2 = cv::imread(fileName.toStdString(),IMREAD_COLOR); // 讀入影像
if(!imgSrc2.empty()) { // 若影像不空
int fw = ui->txbFrameW->text().toInt(); // 取得圖框寬度
int fh = ui->txbFrameH->text().toInt(); // 取得圖框高度
int bw = ui->txbBannerW->text().toInt(); // 取得橫幅寬度
int bh = ui->txbBannerH->text().toInt(); // 取得橫幅高度
cv::resize(imgSrc2,imgF2,cvSize(fw,fh)); // 將原始影像縮到指定圖框尺寸
imgLCDF2 = Mat::zeros(cv::Size(fw,fh),CV_8UC2); // 清除圖框影像緩衝區
imgLCDB2 = Mat::zeros(cv::Size(bw,bh),CV_8UC2); // 清除橫幅影像緩衝區
ShowFrame(imgF2, ui->pbxF2); // 將圖框影像秀在標籤上
ui->btnGoB2->setEnabled(true); // 致能[更新]按鍵
}
}
// 載入圖框影像三
void MainWindow::on_btnLoadF3_clicked()
{
fileName = QFileDialog::getOpenFileName(this,tr("Open File")); // 開啟檔案對話盒並取得檔名
imgSrc3 = cv::imread(fileName.toStdString(),IMREAD_COLOR); // 讀入影像
if(!imgSrc3.empty()) { // 若影像不空
int fw = ui->txbFrameW->text().toInt(); // 取得圖框寬度
int fh = ui->txbFrameH->text().toInt(); // 取得圖框高度
int bw = ui->txbBannerW->text().toInt(); // 取得橫幅寬度
int bh = ui->txbBannerH->text().toInt(); // 取得橫幅高度
cv::resize(imgSrc3,imgF3,cvSize(fw,fh)); // 將原始影像縮到指定圖框尺寸
imgLCDF3 = Mat::zeros(cv::Size(fw,fh),CV_8UC2); // 清除圖框影像緩衝區
imgLCDB3 = Mat::zeros(cv::Size(bw,bh),CV_8UC2); // 清除橫幅影像緩衝區
ShowFrame(imgF3, ui->pbxF3); // 將圖框影像秀在標籤上
ui->btnGoB3->setEnabled(true); // 致能[更新]按鍵
}
}
// 變更橫幅一背景色彩
void MainWindow::on_btnBGColorB1_clicked()
{
QColorDialog colorDlg;
colorDlg.exec(); // 開啟色彩拾取盒
BGColorB1 = colorDlg.selectedColor(); // 設定橫幅背景色彩
SetLabelColor(ui->labBGColorB1, BGColorB1); // 設定標籤色彩
ui->btnGoB1->click(); // 代理按下[更新]鍵
}
// 變更橫幅一前景(文字)色彩
void MainWindow::on_btnFGColorB1_clicked()
{
QColorDialog colorDlg;
colorDlg.exec(); // 開啟色彩拾取盒
FGColorB1 = colorDlg.selectedColor(); // 設定橫幅前景(文字)色彩
SetLabelColor(ui->labFGColorB1, FGColorB1); // 設定標籤色彩
ui->btnGoB1->click(); // 代理按下[更新]鍵
}
// 變更橫幅二背景色彩
void MainWindow::on_btnBGColorB2_clicked()
{
QColorDialog colorDlg;
colorDlg.exec(); // 開啟色彩拾取盒
BGColorB2 = colorDlg.selectedColor(); // 設定橫幅背景色彩
SetLabelColor(ui->labBGColorB2, BGColorB2); // 設定標籤色彩
ui->btnGoB2->click(); // 代理按下[更新]鍵
}
// 變更橫幅二前景(文字)色彩
void MainWindow::on_btnFGColorB2_clicked()
{
QColorDialog colorDlg;
colorDlg.exec(); // 開啟色彩拾取盒
FGColorB2 = colorDlg.selectedColor(); // 設定橫幅前景(文字)色彩
SetLabelColor(ui->labFGColorB2, FGColorB2); // 設定標籤色彩
ui->btnGoB2->click(); // 代理按下[更新]鍵
}
// 變更橫幅三背景色彩
void MainWindow::on_btnBGColorB3_clicked()
{
QColorDialog colorDlg;
colorDlg.exec(); // 開啟色彩拾取盒
BGColorB3 = colorDlg.selectedColor(); // 設定橫幅背景色彩
SetLabelColor(ui->labBGColorB3, BGColorB3); // 設定標籤色彩
ui->btnGoB3->click(); // 代理按下[更新]鍵
}
// 變更橫幅三前景(文字)色彩
void MainWindow::on_btnFGColorB3_clicked()
{
QColorDialog colorDlg;
colorDlg.exec(); // 開啟色彩拾取盒
FGColorB3 = colorDlg.selectedColor(); // 設定橫幅前景(文字)色彩
SetLabelColor(ui->labFGColorB3, FGColorB3); // 設定標籤色彩
ui->btnGoB3->click(); // 代理按下[更新]鍵
}
// 更新橫幅一(含色彩及字體)
void MainWindow::on_btnGoB1_clicked()
{
int bw = ui->txbBannerW->text().toInt(); // 取得橫幅寬度
int bh = ui->txbBannerH->text().toInt(); // 取得橫幅高度
QImage imgB1Q = QImage(bw,bh, QImage::Format_RGB888); // 宣告影像暫存區(RGB888)
QPainter painter(&imgB1Q); // 宣告繪圖區
painter.setBrush(BGColorB1); // 設定繪圖區筆刷(背景)色
painter.setPen(BGColorB1); // 設定繪圖區彩筆(前景)色,去除邊框
painter.drawRect(imgB1Q.rect()); // 設定繪圖區尺寸
painter.setPen(FGColorB1); // 設定繪圖區彩筆(前景)色
painter.setFont(fontB1); // 設定繪圖區字體
painter.drawText(imgB1Q.rect(), Qt::AlignCenter,ui->txbB1->text()); // 將文字繪至繪圖區
ui->pbxB1->setPixmap(QPixmap::fromImage(imgB1Q)); // 將繪好的文字區設定至標籤
ui->pbxB1->setAlignment(Qt::AlignCenter); // 設定置中對齊
Mat matROI = imgF1(Rect(0,140,220,36)); // 設定圖框影像預備放橫幅位置
//設定cv::Mat空白繪圖區,從QImage轉到cv::Mat
Mat matPainter = cv::Mat(imgB1Q.height(), imgB1Q.width(), CV_8UC3, imgB1Q.bits(), imgB1Q.bytesPerLine());
cvtColor(matPainter, matPainter, CV_RGB2BGR); // 將色彩從BGR888轉到RGB888
matPainter.copyTo(imgB1); // 將橫幅繪圖區複製到橫幅影像區
painter.end(); // 結束繪圖區
if(ui->txbB1->text() != 0 && !ui->rdbNoneB1->isChecked()){ // 若文字內容不為空且橫幅不是選擇不顯示模式
imgB1.copyTo(matROI); // 則將橫幅影像貼到圖框影像中指定位置
}
else{
cv::resize(imgSrc1,imgF1,imgF1.size()); // 否則重新以原始影像縮至圖框影像中
}
ShowFrame(imgF1, ui->pbxF1); // 顯示圖框(含橫幅)影像
}
// 變更橫幅一字體
void MainWindow::on_btnFontB1_clicked()
{
QFontDialog fontDlg;
fontDlg.exec(); // 開啟字體選擇對話盒
fontB1 = fontDlg.selectedFont(); // 取得字體參數
ui->btnGoB1->click(); // 代理按下[更新]鍵
}
// 更新橫幅二(含色彩及字體)
void MainWindow::on_btnGoB2_clicked()
{
int bw = ui->txbBannerW->text().toInt(); // 取得橫幅寬度
int bh = ui->txbBannerH->text().toInt(); // 取得橫幅高度
QImage imgB2Q = QImage(bw, bh, QImage::Format_RGB888); // 宣告影像暫存區(RGB888)
QPainter painter(&imgB2Q); // 宣告繪圖區
painter.setBrush(BGColorB2); // 設定繪圖區筆刷(背景)色
painter.setPen(BGColorB2); // 設定繪圖區彩筆(前景)色,去除邊框
painter.drawRect(imgB2Q.rect()); // 設定繪圖區尺寸
painter.setPen(FGColorB2); // 設定繪圖區彩筆(前景)色
painter.setFont(fontB2); // 設定繪圖區字體
painter.drawText(imgB2Q.rect(), Qt::AlignCenter,ui->txbB2->text()); // 將文字繪至繪圖區
ui->pbxB2->setPixmap(QPixmap::fromImage(imgB2Q)); // 將繪好的文字區設定至標籤
ui->pbxB2->setAlignment(Qt::AlignCenter); // 設定置中對齊
Mat matROI = imgF2(Rect(0,140,220,36)); // 設定圖框影像預備放橫幅位置
//設定cv::Mat空白繪圖區,從QImage轉到cv::Mat
Mat matPainter = cv::Mat(imgB2Q.height(), imgB2Q.width(), CV_8UC3, imgB2Q.bits(), imgB2Q.bytesPerLine());
cvtColor(matPainter, matPainter, CV_RGB2BGR); // 將色彩從BGR888轉到RGB888
matPainter.copyTo(imgB2); // 將橫幅繪圖區複製到橫幅影像區
painter.end(); // 結束繪圖區
if(ui->txbB2->text() != 0 && !ui->rdbNoneB2->isChecked()){ // 若文字內容不為空且橫幅不是選擇不顯示模式
imgB2.copyTo(matROI); // 則將橫幅影像貼到圖框影像中指定位置
}
else{
cv::resize(imgSrc2,imgF2,imgF2.size()); // 否則重新以原始影像縮至圖框影像中
}
ShowFrame(imgF2, ui->pbxF2); // 顯示圖框(含橫幅)影像
}
// 變更橫幅二字體
void MainWindow::on_btnFontB2_clicked()
{
QFontDialog fontDlg;
fontDlg.exec(); // 開啟字體選擇對話盒
fontB2 = fontDlg.selectedFont(); // 取得字體參數
ui->btnGoB2->click(); // 代理按下[更新]鍵
}
// 更新橫幅三(含色彩及字體)
void MainWindow::on_btnGoB3_clicked()
{
int bw = ui->txbBannerW->text().toInt(); // 取得橫幅寬度
int bh = ui->txbBannerH->text().toInt(); // 取得橫幅高度
QImage imgB3Q = QImage(bw, bh, QImage::Format_RGB888); // 宣告影像暫存區(RGB888)
QPainter painter(&imgB3Q); // 宣告繪圖區
painter.setBrush(BGColorB3); // 設定繪圖區筆刷(背景)色
painter.setPen(BGColorB3); // 設定繪圖區彩筆(前景)色,去除邊框
painter.drawRect(imgB3Q.rect()); // 設定繪圖區尺寸
painter.setPen(FGColorB3); // 設定繪圖區彩筆(前景)色
painter.setFont(fontB3); // 設定繪圖區字體
painter.drawText(imgB3Q.rect(), Qt::AlignCenter,ui->txbB3->text()); // 將文字繪至繪圖區
ui->pbxB3->setPixmap(QPixmap::fromImage(imgB3Q)); // 將繪好的文字區設定至標籤
ui->pbxB3->setAlignment(Qt::AlignCenter); // 設定置中對齊
Mat matROI = imgF3(Rect(0,140,220,36)); // 設定圖框影像預備放橫幅位置
//設定cv::Mat空白繪圖區,從QImage轉到cv::Mat
Mat matPainter= cv::Mat(imgB3Q.height(), imgB3Q.width(), CV_8UC3, imgB3Q.bits(), imgB3Q.bytesPerLine());
cvtColor(matPainter, matPainter, CV_RGB2BGR); // 將色彩從BGR888轉到RGB888
matPainter.copyTo(imgB3); // 將橫幅繪圖區複製到橫幅影像區
painter.end(); // 結束繪圖區
if(ui->txbB3->text() != 0 && !ui->rdbNoneB3->isChecked()){ // 若文字內容不為空且橫幅不是選擇不顯示模式
imgB3.copyTo(matROI); // 則將橫幅影像貼到圖框影像中指定位置
}
else{
cv::resize(imgSrc3,imgF3,imgF3.size()); // 否則重新以原始影像縮至圖框影像中
}
ShowFrame(imgF3, ui->pbxF3); // 顯示圖框(含橫幅)影像
}
// 變更橫幅三字體
void MainWindow::on_btnFontB3_clicked()
{
QFontDialog fontDlg;
fontDlg.exec(); // 開啟字體選擇對話盒
fontB3 = fontDlg.selectedFont(); // 取得字體參數
ui->btnGoB3->click(); // 代理按下[更新]鍵
}
// 圖框一顯示停留時間變更
void MainWindow::on_spbF1_valueChanged(double arg1)
{
disp_timerF1 = disp_timerB1 = (int)(arg1*10); // 取得圖框顯示時間(單位乘10)
}
// 圖框二顯示停留時間變更
void MainWindow::on_spbF2_valueChanged(double arg1)
{
disp_timerF2 = disp_timerB2 = (int)(arg1*10); // 取得圖框顯示時間(單位乘10)
}
// 圖框三顯示停留時間變更
void MainWindow::on_spbF3_valueChanged(double arg1)
{
disp_timerF3 = disp_timerB3 = (int)(arg1*10); // 取得圖框顯示時間(單位乘10)
}
// 橫幅一顯示模式切換到固定模式
void MainWindow::on_rdbFixB1_clicked()
{
disp_modeB1 = 0; // 顯示模式編號設定為0
}
// 橫幅一顯示模式切換到交替閃爍模式
void MainWindow::on_rdbBlinkB1_clicked()
{
disp_modeB1 = 1; // 顯示模式編號設定為1
}
// 橫幅一顯示模式切換到不顯示模式
void MainWindow::on_rdbNoneB1_clicked()
{
disp_modeB1 = 2; // 顯示模式編號設定為2
}
// 橫幅二顯示模式切換到固定模式
void MainWindow::on_rdbFixB2_clicked()
{
disp_modeB2 = 0; // 顯示模式編號設定為0
}
// 橫幅二顯示模式切換到交替閃爍模式
void MainWindow::on_rdbBlinkB2_clicked()
{
disp_modeB2 = 1; // 顯示模式編號設定為1
}
// 橫幅二顯示模式切換到不顯示模式
void MainWindow::on_rdbNoneB2_clicked()
{
disp_modeB2 = 2; // 顯示模式編號設定為2
}
// 橫幅三顯示模式切換到固定模式
void MainWindow::on_rdbFixB3_clicked()
{
disp_modeB3 = 0; // 顯示模式編號設定為0
}
// 橫幅三顯示模式切換到交替閃爍模式
void MainWindow::on_rdbBlinkB3_clicked()
{
disp_modeB3 = 1; // 顯示模式編號設定為1
}
// 橫幅三顯示模式切換到不顯示模式
void MainWindow::on_rdbNoneB3_clicked()
{
disp_modeB3 = 2; // 顯示模式編號設定為2
}
OpenQSignage開源迷你電子看板(Arduino LCD動畫胸牌)
OpenQSignage開源迷你電子看板(Arduino LCD動畫胸牌)#1_硬體設計說明
OpenQSignage開源迷你電子看板(Arduino LCD動畫胸牌)#2_Arduino程式說明
OpenQSignage開源迷你電子看板(Arduino LCD動畫胸牌)#3_PC程式說明
沒有留言:
張貼留言