摘要
本篇博文記錄一下,用VS+Qt+Halcon實現對圖片的讀取以及滑鼠縮放,移動(滑鼠事件呼叫了halcon自帶的運算元)的過程。以及遇到的坑.....??
先來看一下動態效果圖:
主要控制元件:
- 新增一個Label控制元件,物件名設為label,用於顯示圖片,並將背景設為黑色,設定方法為:選中Label控制元件,在屬性編輯器中找到styleSheet屬性,在其後的值中輸入background-color:black即可;
- 新增四個Push Button控制元件,如上圖所示從左至右,物件名依次為:btn_prePic、btn_openPic、btn_nextPic,btn_resetPic,用於開啟圖片和前後瀏覽,以及恢復原圖;
- 新增一個Label,物件名設為label_status,用於實時顯示座標和灰度值;
- 將label_show控制元件提升為CMyLabel類,用於接收滑鼠事件。
程式碼例程
在Visual Studio中新建一個Qt GUI專案,名稱設為BrowsePic,並新建Mylabel類(繼承自QLabel)用於label控制元件的提升。
- Mylabel.h
#pragma once #include "qlabel.h" #include"QWheelEvent" #include<HalconCpp.h> using namespace HalconCpp; class Mylabel : public QLabel { Q_OBJECT public: Mylabel(QWidget* parent = Q_NULLPTR); ~Mylabel(); //設定Halcon影像和Halcon視窗控制程式碼,使用者響應滑鼠事件後實時更新影像 void setHalconWnd(HObject img, HTuple hHalconID, QLabel* label); //滑鼠滾輪縮放事件 void wheelEvent(QWheelEvent* ev); //滑鼠按下事件 void mousePressEvent(QMouseEvent* ev); //滑鼠釋放事件 void mouseReleaseEvent(QMouseEvent* ev); //滑鼠移動事件 void mouseMoveEvent(QMouseEvent* ev); public: HTuple m_labelID; //Qt標籤控制程式碼 HTuple m_hHalconID; //Halcon視窗控制程式碼 HObject m_currentImg; //當前的影像 //主介面顯示座標的標籤 QLabel* m_label; //滑鼠按下的位置 HTuple m_tMouseDownRow; HTuple m_tMouseDownCol; bool m_bIsMove; //是否移動影像標識 };
- Mylabel.cpp
#include "Mylabel.h" //定義單步放大倍率 #define ZOOMRATIO 2.0 Mylabel::Mylabel(QWidget* parent) : QLabel(parent) { m_bIsMove = false; this->setMouseTracking(true); } Mylabel::~Mylabel() { } //設定Halcon影像和Halcon視窗控制程式碼,使用者響應滑鼠事件後實時更新影像 void Mylabel::setHalconWnd(HObject img, HTuple hHalconID, QLabel* label) { m_hHalconID = hHalconID; m_currentImg = img; m_label = label; } //滑鼠滾輪縮放事件,用於縮放影像 void Mylabel::wheelEvent(QWheelEvent* ev) { double Zoom; //放大或縮小倍率 HTuple mouseRow, mouseCol, Button; HTuple startRowBf, startColBf, endRowBf, endColBf, Ht, Wt, startRowAft, startColAft, endRowAft, endColAft; //滾輪前滑,放大 if (ev->delta()>0) { Zoom = ZOOMRATIO; } else//否則縮小 { Zoom = 1 / ZOOMRATIO; } //獲取游標在原圖上的位置,注意是原圖座標,不是Label下的座標 HTuple hv_Exception, hv_ErrMsg; try { GetMposition(m_hHalconID, &mouseRow, &mouseCol, &Button); } catch (HException& HDevExpDefaultException) { return; } //獲取原圖顯示的部分,注意也是原圖座標 GetPart(m_hHalconID, &startRowBf, &startColBf, &endRowBf, &endColBf); //縮放前顯示的影像寬高 Ht = endRowBf - startRowBf; Wt = endColBf - startColBf; //普通版halcon能處理的影像最大尺寸是32K*32K。如果無限縮小原影像,導致顯示的影像超出限制,則會造成程式崩潰 if (Ht*Wt<20000*20000||Zoom==ZOOMRATIO) { //計算縮放後的影像區域 startRowAft = mouseRow - ((mouseRow - startRowBf) / Zoom); startColAft = mouseCol - ((mouseCol - startColBf) / Zoom); endRowAft = startRowAft + (Ht / Zoom); endColAft = startColAft + (Wt / Zoom); //如果放大過大,則返回 if (endRowAft - startRowAft < 2) { return; } if (m_hHalconID != NULL) { //如果有影像,則先清空影像 DetachBackgroundFromWindow(m_hHalconID); } SetPart(m_hHalconID, startRowAft, startColAft, endRowAft, endColAft); AttachBackgroundToWindow(m_currentImg, m_hHalconID); } } void Mylabel::mousePressEvent(QMouseEvent* ev) { HTuple mouseRow, mouseCol, Button; try { GetMposition(m_hHalconID, &mouseRow, &mouseCol, &Button); } catch (HException) { return; } //滑鼠按下時的行列座標 m_tMouseDownRow = mouseRow; m_tMouseDownCol = mouseCol; m_bIsMove = true; } //滑鼠釋放事件 void Mylabel::mouseReleaseEvent(QMouseEvent* ev) { m_bIsMove = false; } //滑鼠移動事件 void Mylabel::mouseMoveEvent(QMouseEvent* ev) { HTuple startRowBf, startColBf, endRowBf, endColBf, mouseRow, mouseCol, Button; try { GetMposition(m_hHalconID, &mouseRow, &mouseCol, &Button); } catch (HException) { return; } //滑鼠按下並移動時,移動影像,否則只顯示座標 if (m_bIsMove) { //計算移動值 double RowMove = mouseRow[0].D() - m_tMouseDownRow[0].D(); double ColMove = mouseCol[0].D() - m_tMouseDownCol[0].D(); //得到當前的視窗座標 GetPart(m_hHalconID, &startRowBf, &startColBf, &endRowBf, &endColBf); //移動影像 if (m_hHalconID!=NULL) { //如果有影像,則先清空影像 DetachBackgroundFromWindow(m_hHalconID); } SetPart(m_hHalconID, startRowBf - RowMove, startColBf - ColMove, endRowBf - RowMove, endColBf - ColMove); AttachBackgroundToWindow(m_currentImg, m_hHalconID); } //獲取灰度值 HTuple pointGray; try { GetGrayval(m_currentImg, mouseRow, mouseCol, &pointGray); } catch (HException) { m_label->setText(QString::fromLocal8Bit("X座標:- Y座標:- 灰度值:-")); return; } //設定座標 m_label->setText(QString::fromLocal8Bit("X座標:%1 Y座標:%2 灰度值:%3").arg(mouseCol[0].D()).arg(mouseRow[0].D()).arg(pointGray[0].D())); }
- BrowsePic.h
#pragma once #include <QtWidgets/QWidget> #include "ui_BrowsePic.h" #include<HalconCpp.h> #include"qtoolbar.h" using namespace HalconCpp; #pragma execution_character_set("utf-8"); class BrowsePic : public QWidget { Q_OBJECT public: BrowsePic(QWidget *parent = Q_NULLPTR); ~BrowsePic(); //初始化 void init(); //顯示影像 void showImg(); int currentIndex; //顯示影像的控制元件id HTuple m_hLabelID; //QLabel控制元件控制程式碼 HTuple m_hHalconID; //Halcon顯示視窗控制程式碼 //原始影像的尺寸 HTuple m_imgWidth, m_imgHeight; //圖片路徑列表 HTuple m_imgFiles; //當前影像 HObject m_hCurrentImg; //縮放後的影像 HObject m_hResizedImg; //縮放係數 HTuple m_hvScaledRate; //縮放後影像的大小 HTuple m_scaledHeight, m_scaledWidth; QToolBar* m_toolBar; public slots: //開啟圖片 void on_btn_openPic_clicked(); //瀏覽前一張 void on_btn_prePic_clicked(); //瀏覽後一張 void on_btn_nextPic_clicked(); //恢復圖片 void on_btn_resetPic_clicked(); private: Ui::BrowsePicClass ui; };
- BrowsePic.cpp
#include "browsepic.h" #include"Mylabel.h" #include <QFileDialog> #include <QFileInfo> BrowsePic::BrowsePic(QWidget *parent) : QWidget(parent) { ui.setupUi(this); init(); } BrowsePic::~BrowsePic() { } void BrowsePic::init() { //設定halcon的檔案路徑為utf8,解決中文亂碼 SetSystem("filename_encoding", "utf8"); //生成空影像 GenEmptyObj(&m_hCurrentImg); m_hHalconID = NULL; m_hLabelID = (Hlong)ui.label->winId(); currentIndex = -1; } //顯示影像 void BrowsePic::showImg() { if (m_hHalconID!=NULL) { //如果有影像,則先清空影像 DetachBackgroundFromWindow(m_hHalconID); } else { //開啟視窗 OpenWindow(0, 0, ui.label->width(), ui.label->height(), m_hLabelID, "visible", "", &m_hHalconID); } ui.label-> setHalconWnd(m_hCurrentImg, m_hHalconID, ui.label_status); //獲取影像大小 GetImageSize(m_hCurrentImg, &m_imgWidth, &m_imgHeight); //獲取縮放係數 TupleMin2(1.0 * ui.label->width() / m_imgWidth, 1.0 * ui.label->height() / m_imgHeight, &m_hvScaledRate); //縮放影像 ZoomImageFactor(m_hCurrentImg, &m_hResizedImg, m_hvScaledRate, m_hvScaledRate, "constant"); //獲取縮放後的大小 GetImageSize(m_hResizedImg, &m_scaledWidth, &m_scaledHeight); //開啟視窗 if (1.0 * ui.label->width() / m_imgWidth < 1.0 * ui.label->height() / m_imgHeight) { SetWindowExtents(m_hHalconID, ui.label->height() / 2.0 - m_scaledHeight / 2.0, 0, ui.label->width(), m_scaledHeight); } else { SetWindowExtents(m_hHalconID, 0, ui.label->width() / 2.0 - m_scaledWidth / 2.0, m_scaledWidth, ui.label->height()); } SetPart(m_hHalconID, 0, 0, m_imgHeight - 1, m_imgWidth - 1); AttachBackgroundToWindow(m_hCurrentImg, m_hHalconID); } //開啟圖片 void BrowsePic::on_btn_openPic_clicked() { QString path = QFileDialog::getOpenFileName(this, "載入影像", "./", "影像檔案(*.bmp *.png *.jpg)"); QFileInfo fileInfo(path); QString dir = fileInfo.path(); if (!path.isEmpty()) { ListFiles(dir.toStdString().c_str(), "files", &m_imgFiles); TupleRegexpSelect(m_imgFiles, HTuple("\\.bmp|png|jpg").Append("ignore_case"), &m_imgFiles); for (int i = 0; i < m_imgFiles.Length(); i++) { QString currentPath = m_imgFiles[i]; currentPath.replace("\\", "/"); if (currentPath == path) { currentIndex = i; ReadImage(&m_hCurrentImg, m_imgFiles[i]); showImg(); } } } } //瀏覽前一張 void BrowsePic::on_btn_prePic_clicked() { if (currentIndex > 0) { currentIndex--; ReadImage(&m_hCurrentImg, m_imgFiles[currentIndex]); showImg(); } } //瀏覽後一張 void BrowsePic::on_btn_nextPic_clicked() { if (currentIndex >= 0 && currentIndex < m_imgFiles.Length() - 1) { currentIndex++; ReadImage(&m_hCurrentImg, m_imgFiles[currentIndex]); showImg(); } } //恢復圖片 void BrowsePic::on_btn_resetPic_clicked() { showImg(); }
關鍵程式碼解釋
1️⃣Qt函式與Halcon運算元獲取的檔案路徑字串的區別
- Halcon運算元獲取的檔案路徑格式
list_files()的原型如下:
第一個引數為路徑,提取的檔案路徑格式與引數Directory的形式有關,在HDevelop中測試:
– Directory以"\\"分隔時,即list_files ('E:\\TEST', 'files', Files)
– Directory以“/”分隔時,即list_files ('E:/TEST', 'files', Files)
可以發現兩種方式提取的檔案路徑字串的區別。
-
Qt函式獲取的檔案路徑格式
getOpenFileName()獲得的路徑:
如何將二者路徑保持一致?
先讀取halcon運算元獲取的路徑:
QString currentPath = m_imgFiles[i];
然後將" \ "全部換成" /":
currentPath.replace("\\", "/");
2️⃣在VS中使用Halcon時的編碼及中文亂碼問題
預設條件下,可使用以下C++語句獲取Halcon的檔名編碼:
HTuple codeType; get_system("filename_encoding", &codeType); QString strCodeType = codeType[0].S();
可以發現預設的編碼是locale,此時用Halcon運算元list_files獲取的檔案路徑中如果包含中文,則會出現亂碼
解決方法:將Halcon的檔名編碼格式設定為utf8,程式碼如下:
set_system("filename_encoding", "utf8");
參考連結:(4條訊息) VS+Qt應用開發-使用Halcon運算元實現從資料夾開啟圖片、前後瀏覽、縮放居中顯示_羽士的部落格-CSDN部落格